Merge commit 'f057ecd724f3b2ff84c69304e34c2ec3006402ac' as 'api'
This commit is contained in:
commit
67b190d238
27 changed files with 8 additions and 654 deletions
|
@ -5,6 +5,6 @@ end_of_line = lf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
|
|
||||||
[*.cs]
|
[*.proto]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,6 +1,2 @@
|
||||||
bin/
|
|
||||||
obj/
|
|
||||||
.idea/
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.idea/
|
||||||
INetMock.sln.DotSettings.user
|
|
36
INetMock.sln
36
INetMock.sln
|
@ -1,36 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "INetMock.Client", "src\INetMock.Client\INetMock.Client.csproj", "{4B1CFFB0-23B5-4238-BFCC-4155F459FF8E}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{DF7A15B0-72D0-4BA1-9C9E-424343F6D530}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
.gitignore = .gitignore
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{07100561-E3C0-4B95-92E1-D2D3BA12C3A6}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E7144CE4-3E55-431B-8835-E804C664A694}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "INetMock.Client.Test", "test\INetMock.Client.Test\INetMock.Client.Test.csproj", "{BFC06300-C82F-4A24-A10E-5C7D66208280}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{4B1CFFB0-23B5-4238-BFCC-4155F459FF8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4B1CFFB0-23B5-4238-BFCC-4155F459FF8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4B1CFFB0-23B5-4238-BFCC-4155F459FF8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4B1CFFB0-23B5-4238-BFCC-4155F459FF8E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{BFC06300-C82F-4A24-A10E-5C7D66208280}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{BFC06300-C82F-4A24-A10E-5C7D66208280}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{BFC06300-C82F-4A24-A10E-5C7D66208280}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{BFC06300-C82F-4A24-A10E-5C7D66208280}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
{4B1CFFB0-23B5-4238-BFCC-4155F459FF8E} = {07100561-E3C0-4B95-92E1-D2D3BA12C3A6}
|
|
||||||
{BFC06300-C82F-4A24-A10E-5C7D66208280} = {E7144CE4-3E55-431B-8835-E804C664A694}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -1,2 +1 @@
|
||||||
# client-dotnet
|
# INetMock protobuf API
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
charset = utf-8
|
|
||||||
|
|
||||||
[*.proto]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
2
api.bak/.gitignore
vendored
2
api.bak/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
|
@ -1 +0,0 @@
|
||||||
# INetMock protobuf API
|
|
|
@ -4,7 +4,6 @@ option go_package = "gitlab.com/inetmock/inetmock/pkg/audit/details";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.audit.details";
|
option java_package = "com.github.baez90.inetmock.audit.details";
|
||||||
option java_outer_classname = "HandlerEventProto";
|
option java_outer_classname = "HandlerEventProto";
|
||||||
option csharp_namespace = "INetMock.Client.Audit.Details";
|
|
||||||
|
|
||||||
package inetmock.audit.details;
|
package inetmock.audit.details;
|
||||||
|
|
|
@ -4,7 +4,6 @@ option go_package = "gitlab.com/inetmock/inetmock/pkg/audit/details";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.audit.details";
|
option java_package = "com.github.baez90.inetmock.audit.details";
|
||||||
option java_outer_classname = "HandlerEventProto";
|
option java_outer_classname = "HandlerEventProto";
|
||||||
option csharp_namespace = "INetMock.Client.Audit.Details";
|
|
||||||
|
|
||||||
package inetmock.audit.details;
|
package inetmock.audit.details;
|
||||||
|
|
||||||
|
@ -30,4 +29,4 @@ message HTTPDetailsEntity {
|
||||||
string uri = 3;
|
string uri = 3;
|
||||||
string proto = 4;
|
string proto = 4;
|
||||||
map<string, HTTPHeaderValue> headers = 5;
|
map<string, HTTPHeaderValue> headers = 5;
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@ option go_package = "gitlab.com/inetmock/inetmock/pkg/audit";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.audit";
|
option java_package = "com.github.baez90.inetmock.audit";
|
||||||
option java_outer_classname = "HandlerEventProto";
|
option java_outer_classname = "HandlerEventProto";
|
||||||
option csharp_namespace = "INetMock.Client.Audit";
|
|
||||||
|
|
||||||
package inetmock.audit;
|
package inetmock.audit;
|
||||||
|
|
||||||
|
@ -49,4 +48,4 @@ message EventEntity {
|
||||||
uint32 destinationPort = 8;
|
uint32 destinationPort = 8;
|
||||||
TLSDetailsEntity tls = 9;
|
TLSDetailsEntity tls = 9;
|
||||||
google.protobuf.Any protocolDetails = 10;
|
google.protobuf.Any protocolDetails = 10;
|
||||||
}
|
}
|
|
@ -4,9 +4,8 @@ option go_package = "gitlab.com/inetmock/inetmock/pkg/rpc";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.rpc";
|
option java_package = "com.github.baez90.inetmock.rpc";
|
||||||
option java_outer_classname = "AuditProto";
|
option java_outer_classname = "AuditProto";
|
||||||
option csharp_namespace = "INetMock.Client.Rpc";
|
|
||||||
|
|
||||||
import 'proto/audit/event_entity.proto';
|
import 'pkg/audit/event_entity.proto';
|
||||||
|
|
||||||
package inetmock.rpc;
|
package inetmock.rpc;
|
||||||
|
|
||||||
|
@ -50,4 +49,4 @@ service Audit {
|
||||||
rpc RegisterFileSink (RegisterFileSinkRequest) returns (RegisterFileSinkResponse);
|
rpc RegisterFileSink (RegisterFileSinkRequest) returns (RegisterFileSinkResponse);
|
||||||
rpc RemoveFileSink (RemoveFileSinkRequest) returns (RemoveFileSinkResponse);
|
rpc RemoveFileSink (RemoveFileSinkRequest) returns (RemoveFileSinkResponse);
|
||||||
rpc ListSinks(ListSinksRequest) returns (ListSinksResponse);
|
rpc ListSinks(ListSinksRequest) returns (ListSinksResponse);
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@ option go_package = "gitlab.com/inetmock/inetmock/internal/rpc";
|
||||||
option java_multiple_files = true;
|
option java_multiple_files = true;
|
||||||
option java_package = "com.github.baez90.inetmock.rpc";
|
option java_package = "com.github.baez90.inetmock.rpc";
|
||||||
option java_outer_classname = "HealthProto";
|
option java_outer_classname = "HealthProto";
|
||||||
option csharp_namespace = "INetMock.Client.Rpc";
|
|
||||||
|
|
||||||
package inetmock.rpc;
|
package inetmock.rpc;
|
||||||
|
|
||||||
|
@ -32,4 +31,4 @@ message ComponentHealth {
|
||||||
message HealthResponse {
|
message HealthResponse {
|
||||||
HealthState overallHealthState = 1;
|
HealthState overallHealthState = 1;
|
||||||
map<string, ComponentHealth> componentsHealth = 2;
|
map<string, ComponentHealth> componentsHealth = 2;
|
||||||
}
|
}
|
|
@ -1,89 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using Google.Protobuf.WellKnownTypes;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GenericDetails(Any? any)
|
|
||||||
{
|
|
||||||
_detailsAny = any;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
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();
|
|
||||||
return new DnsDetails(gd._detailsAny);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record HttpDetails : EventDetails
|
|
||||||
{
|
|
||||||
public HttpDetails()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpDetails(Any? any)
|
|
||||||
{
|
|
||||||
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; }
|
|
||||||
public string Proto { get; init; }
|
|
||||||
public HttpHeaders Headers { get; init; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public record DnsDetails : EventDetails
|
|
||||||
{
|
|
||||||
public DnsDetails()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public DNSOpCode OpCode { get; init; }
|
|
||||||
|
|
||||||
public IReadOnlyList<DNSQuestionEntity> Questions { get; init; }
|
|
||||||
|
|
||||||
public DnsDetails(Any? any)
|
|
||||||
{
|
|
||||||
if(any == null || any.Value == null) return;
|
|
||||||
|
|
||||||
var entity = DNSDetailsEntity.Parser.ParseFrom(any.Value);
|
|
||||||
OpCode = entity.Opcode;
|
|
||||||
Questions = entity.Questions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Audit
|
|
||||||
{
|
|
||||||
public record Event<T> where T : EventDetails, new()
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
(_, AppProtocol.Dns) => new DnsDetails(entity.ProtocolDetails) as T,
|
|
||||||
(_, AppProtocol.Http or AppProtocol.HttpProxy) => new HttpDetails(entity.ProtocolDetails) as T,
|
|
||||||
(_, _) => new EmptyDetails() as T
|
|
||||||
};
|
|
||||||
|
|
||||||
Id = entity.Id;
|
|
||||||
Timestamp = entity.Timestamp.ToDateTimeOffset();
|
|
||||||
Transport = entity.Transport;
|
|
||||||
SourceIp = new IPAddress(entity.SourceIP.Span);
|
|
||||||
SourcePort = Convert.ToUInt16(entity.SourcePort);
|
|
||||||
DestinationIp = new IPAddress(entity.DestinationIP.Span);
|
|
||||||
DestinationPort = Convert.ToUInt16(entity.DestinationPort);
|
|
||||||
TlsDetails = entity.Tls;
|
|
||||||
Application = entity.Application;
|
|
||||||
Details = details;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long Id { get; init; }
|
|
||||||
public DateTimeOffset Timestamp { get; init; }
|
|
||||||
public TransportProtocol Transport { get; init; }
|
|
||||||
public AppProtocol Application { get; init; }
|
|
||||||
public IPAddress SourceIp { get; init; }
|
|
||||||
public IPAddress DestinationIp { get; init; }
|
|
||||||
public ushort SourcePort { get; init; }
|
|
||||||
public ushort DestinationPort { get; init; }
|
|
||||||
public TLSDetailsEntity TlsDetails { get; init; }
|
|
||||||
public T? Details { get; init; }
|
|
||||||
|
|
||||||
public bool CanConvert<TTarget>() where TTarget : EventDetails, new()
|
|
||||||
{
|
|
||||||
if (Details == null) return false;
|
|
||||||
|
|
||||||
return (new TTarget(), Application) switch
|
|
||||||
{
|
|
||||||
(DnsDetails, AppProtocol.Dns) => true,
|
|
||||||
(HttpDetails, AppProtocol.Http or AppProtocol.HttpProxy) => true,
|
|
||||||
(_, _) => false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static explicit operator Event<T>?(Event<GenericDetails> ge)
|
|
||||||
{
|
|
||||||
T? details = null;
|
|
||||||
if (ge.Details != null)
|
|
||||||
{
|
|
||||||
details = ge.Application switch
|
|
||||||
{
|
|
||||||
AppProtocol.Dns => (DnsDetails) ge.Details as T,
|
|
||||||
AppProtocol.Http or AppProtocol.HttpProxy => (HttpDetails) ge.Details as T,
|
|
||||||
_ => new EmptyDetails() as T
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (details == null) return null;
|
|
||||||
|
|
||||||
return new()
|
|
||||||
{
|
|
||||||
Id = ge.Id,
|
|
||||||
Timestamp = ge.Timestamp,
|
|
||||||
Transport = ge.Transport,
|
|
||||||
SourceIp = ge.SourceIp,
|
|
||||||
SourcePort = ge.SourcePort,
|
|
||||||
DestinationIp = ge.DestinationIp,
|
|
||||||
DestinationPort = ge.DestinationPort,
|
|
||||||
TlsDetails = ge.TlsDetails,
|
|
||||||
Application = ge.Application,
|
|
||||||
Details = details
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Audit
|
|
||||||
{
|
|
||||||
public sealed class GenericReader : IEventReader<GenericDetails>
|
|
||||||
{
|
|
||||||
private readonly IProtoEventReader _reader;
|
|
||||||
|
|
||||||
public GenericReader(IProtoEventReader reader)
|
|
||||||
{
|
|
||||||
_reader = reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async IAsyncEnumerable<Event<GenericDetails>> ReadAllAsync([EnumeratorCancellation] CancellationToken token = default)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var ev = await ReadAsync(token);
|
|
||||||
if (ev == null)
|
|
||||||
{
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return ev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Event<GenericDetails>?> ReadAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var entity = await _reader.ReadAsync(token);
|
|
||||||
if (entity == null) return null;
|
|
||||||
return new Event<GenericDetails>(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync() => _reader.DisposeAsync();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_reader.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Audit
|
|
||||||
{
|
|
||||||
public interface IEventReader<T>: IDisposable, IAsyncDisposable where T : EventDetails, new()
|
|
||||||
{
|
|
||||||
IAsyncEnumerable<Event<T>> ReadAllAsync(CancellationToken token = default);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns>
|
|
||||||
/// An event as long as underlying stream has data.
|
|
||||||
/// When the end of the stream has been reached it will return null.
|
|
||||||
/// </returns>
|
|
||||||
Task<Event<T>?> ReadAsync(CancellationToken token = default);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using Google.Protobuf.Collections;
|
|
||||||
using INetMock.Client.Audit.Details;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Audit
|
|
||||||
{
|
|
||||||
internal class INetMockHttpHeaders : HttpHeaders
|
|
||||||
{
|
|
||||||
internal INetMockHttpHeaders(MapField<string, HTTPHeaderValue> headers)
|
|
||||||
{
|
|
||||||
foreach (var (key, values) in headers)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(key) || values == null) continue;
|
|
||||||
Add(key, values.Values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Audit
|
|
||||||
{
|
|
||||||
public interface IProtoEventReader : IDisposable, IAsyncDisposable
|
|
||||||
{
|
|
||||||
Task<EventEntity?> ReadAsync(CancellationToken token = default);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
using System.Buffers;
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Google.Protobuf;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Audit
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
_sourceStream = sourceStream;
|
|
||||||
_keepStreamOpen = keepStreamOpen;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<EventEntity?> ReadAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
using var rentedLengthMem = _memoryPool.Rent(4);
|
|
||||||
var lengthMem = rentedLengthMem.Memory.Slice(0, 4);
|
|
||||||
var read = await _sourceStream.ReadAsync(lengthMem, token);
|
|
||||||
if (read != 4)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var messageLength = BinaryPrimitives.ReadInt32BigEndian(lengthMem.Span);
|
|
||||||
using var rentedMsgMem = _memoryPool.Rent(messageLength);
|
|
||||||
var msgMem = rentedMsgMem.Memory.Slice(0, messageLength);
|
|
||||||
read = await _sourceStream.ReadAsync(msgMem, token);
|
|
||||||
if (read != messageLength)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entity = new EventEntity();
|
|
||||||
entity.MergeFrom(msgMem.ToArray());
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
if (!_keepStreamOpen)
|
|
||||||
{
|
|
||||||
await _sourceStream.DisposeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
_memoryPool.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (!_keepStreamOpen)
|
|
||||||
{
|
|
||||||
_sourceStream?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_memoryPool?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Audit
|
|
||||||
{
|
|
||||||
public sealed class TypedReader<T> : IEventReader<T> where T : EventDetails, new()
|
|
||||||
{
|
|
||||||
private readonly IProtoEventReader _reader;
|
|
||||||
|
|
||||||
public TypedReader(IProtoEventReader reader)
|
|
||||||
{
|
|
||||||
_reader = reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async IAsyncEnumerable<Event<T>> ReadAllAsync([EnumeratorCancellation] CancellationToken token = default)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var ev = await ReadAsync(token);
|
|
||||||
if (ev == null)
|
|
||||||
{
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return ev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Event<T>?> ReadAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
var entity = await _reader.ReadAsync(token);
|
|
||||||
if (entity == null) return null;
|
|
||||||
var parsed = new Event<T>(entity);
|
|
||||||
if (parsed.Details == null) continue;
|
|
||||||
return parsed;
|
|
||||||
} while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() => _reader.Dispose();
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync() => _reader.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.14.0" />
|
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.35.0" />
|
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.35.0">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Protobuf Include="proto\rpc\audit.proto" GrpcServices="Client" />
|
|
||||||
<Protobuf Include="proto\rpc\health.proto" GrpcServices="Client" />
|
|
||||||
<Protobuf Include="proto\audit\event_entity.proto" GrpcServices="Client" />
|
|
||||||
<Protobuf Include="proto\audit\details\dns_details.proto" GrpcServices="Client" />
|
|
||||||
<Protobuf Include="proto\audit\details\http_details.proto" GrpcServices="Client" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1 +0,0 @@
|
||||||
../../api/proto/
|
|
|
@ -1,57 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using INetMock.Client.Audit;
|
|
||||||
using INetMock.Client.Test.Hex;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Test.Audit
|
|
||||||
{
|
|
||||||
public class GenericReaderTest
|
|
||||||
{
|
|
||||||
private const string HttpEventPayload = "000000dd120b088092b8c398feffffff01180120022a047f00000132047f00000138d8fc0140504a3308041224544c535f45434448455f45434453415f574954485f4145535f3235365f4342435f5348411a096c6f63616c686f73745282010a34747970652e676f6f676c65617069732e636f6d2f696e65746d6f636b2e61756469742e4854545044657461696c73456e74697479124a12096c6f63616c686f73741a15687474703a2f2f6c6f63616c686f73742f6173646622084854545020312e312a1c0a0641636365707412120a106170706c69636174696f6e2f6a736f6e";
|
|
||||||
private const string DnsEventPayload = "0000003b120b088092b8c398feffffff01180120012a100000000000000000000000000000000132100000000000000000000000000000000138d8fc014050";
|
|
||||||
|
|
||||||
private readonly byte[] _httpEventPayloadBytes;
|
|
||||||
private readonly byte[] _dnsEventPayloadBytes;
|
|
||||||
|
|
||||||
public GenericReaderTest()
|
|
||||||
{
|
|
||||||
_httpEventPayloadBytes = HttpEventPayload.HexToByteArray();
|
|
||||||
_dnsEventPayloadBytes = DnsEventPayload.HexToByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void TestRead_HttpEvent_Success()
|
|
||||||
{
|
|
||||||
await using var protoReader = new ProtoReader(new MemoryStream(_httpEventPayloadBytes));
|
|
||||||
await using var reader = new GenericReader(protoReader);
|
|
||||||
await foreach (var ev in reader.ReadAllAsync())
|
|
||||||
{
|
|
||||||
Assert.NotNull(ev);
|
|
||||||
|
|
||||||
Assert.True(ev.CanConvert<HttpDetails>());
|
|
||||||
Assert.False(ev.CanConvert<DnsDetails>());
|
|
||||||
|
|
||||||
var httpEvent = (Event<HttpDetails>?) ev;
|
|
||||||
var dnsEvent = (Event<DnsDetails>?) ev;
|
|
||||||
|
|
||||||
Assert.NotNull(httpEvent);
|
|
||||||
Assert.Null(dnsEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void TestRead_DnsEvent_Success()
|
|
||||||
{
|
|
||||||
await using var memStream = new MemoryStream(_dnsEventPayloadBytes);
|
|
||||||
await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes));
|
|
||||||
await using var reader = new GenericReader(protoReader);
|
|
||||||
await foreach (var ev in reader.ReadAllAsync())
|
|
||||||
{
|
|
||||||
Assert.NotNull(ev);
|
|
||||||
Assert.True(ev.CanConvert<DnsDetails>());
|
|
||||||
var dnsEvent = (Event<DnsDetails>?) ev;
|
|
||||||
Assert.NotNull(dnsEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using INetMock.Client.Audit;
|
|
||||||
using INetMock.Client.Test.Hex;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Test.Audit
|
|
||||||
{
|
|
||||||
public class TypedReaderTest
|
|
||||||
{
|
|
||||||
private const string HttpEventPayload = "000000dd120b088092b8c398feffffff01180120022a047f00000132047f00000138d8fc0140504a3308041224544c535f45434448455f45434453415f574954485f4145535f3235365f4342435f5348411a096c6f63616c686f73745282010a34747970652e676f6f676c65617069732e636f6d2f696e65746d6f636b2e61756469742e4854545044657461696c73456e74697479124a12096c6f63616c686f73741a15687474703a2f2f6c6f63616c686f73742f6173646622084854545020312e312a1c0a0641636365707412120a106170706c69636174696f6e2f6a736f6e";
|
|
||||||
private const string DnsEventPayload = "0000003b120b088092b8c398feffffff01180120012a100000000000000000000000000000000132100000000000000000000000000000000138d8fc014050";
|
|
||||||
|
|
||||||
private readonly byte[] _httpEventPayloadBytes;
|
|
||||||
private readonly byte[] _dnsEventPayloadBytes;
|
|
||||||
|
|
||||||
public TypedReaderTest()
|
|
||||||
{
|
|
||||||
_httpEventPayloadBytes = HttpEventPayload.HexToByteArray();
|
|
||||||
_dnsEventPayloadBytes = DnsEventPayload.HexToByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void TestRead_HttpEvent_Success()
|
|
||||||
{
|
|
||||||
await using var protoReader = new ProtoReader(new MemoryStream(_httpEventPayloadBytes));
|
|
||||||
await using var reader = new TypedReader<HttpDetails>(protoReader);
|
|
||||||
await foreach (var ev in reader.ReadAllAsync())
|
|
||||||
{
|
|
||||||
Assert.NotNull(ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void TestRead_DnsEvent_Success()
|
|
||||||
{
|
|
||||||
await using var memStream = new MemoryStream(_dnsEventPayloadBytes);
|
|
||||||
await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes));
|
|
||||||
await using var reader = new TypedReader<DnsDetails>(protoReader);
|
|
||||||
await foreach (var ev in reader.ReadAllAsync())
|
|
||||||
{
|
|
||||||
Assert.NotNull(ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace INetMock.Client.Test.Hex
|
|
||||||
{
|
|
||||||
public static class Converter
|
|
||||||
{
|
|
||||||
public static byte[] HexToByteArray(this string hex) {
|
|
||||||
return Enumerable.Range(0, hex.Length)
|
|
||||||
.Where(x => x % 2 == 0)
|
|
||||||
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
|
||||||
<PackageReference Include="xunit" Version="2.4.0" />
|
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
|
||||||
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\src\INetMock.Client\INetMock.Client.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
Loading…
Reference in a new issue