Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/EventStore/src/Eventuous.EventStore/EsdbEventStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ StreamEvent AsStreamEvent(object payload)
payload,
DeserializeMetadata() ?? new Metadata(),
resolvedEvent.Event.ContentType,
resolvedEvent.OriginalEventNumber.ToInt64()
resolvedEvent.Event.EventNumber.ToInt64()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,13 @@ IMessageConsumeContext CreateContext(ResolvedEvent re, CancellationToken cancell
re.Event.EventId.ToString(),
re.Event.EventType,
re.Event.ContentType,
re.OriginalStreamId,
re.Event.EventStreamId,
re.Event.EventNumber,
re.Event.Position.CommitPosition,
_sequence++,
re.Event.Created,
evt,
Options.MetadataSerializer.DeserializeMeta(Options, re.Event.Metadata, re.OriginalStreamId),
Options.MetadataSerializer.DeserializeMeta(Options, re.Event.Metadata, re.Event.EventStreamId),
SubscriptionId,
cancellationToken
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,21 @@ IMessageConsumeContext CreateContext(ResolvedEvent re, CancellationToken cancell
re.Event.ContentType,
re.Event.EventType,
re.Event.Data,
re.OriginalStreamId,
re.Event.EventStreamId,
re.Event.Position.CommitPosition
);

return new MessageConsumeContext(
re.Event.EventId.ToString(),
re.Event.EventType,
re.Event.ContentType,
re.OriginalStreamId,
re.Event.EventStreamId,
GetContextStreamPosition(re),
re.Event.Position.CommitPosition,
re.OriginalEventNumber,
re.Event.Created,
evt,
Options.MetadataSerializer.DeserializeMeta(Options, re.Event.Metadata, re.OriginalStreamId, re.Event.EventNumber),
Options.MetadataSerializer.DeserializeMeta(Options, re.Event.Metadata, re.Event.EventStreamId, re.Event.EventNumber),
SubscriptionId,
cancellationToken
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ IMessageConsumeContext CreateContext(ResolvedEvent re, CancellationToken cancell
re.Event.EventType,
re.Event.ContentType,
re.Event.EventStreamId,
re.OriginalEventNumber,
re.Event.EventNumber,
re.Event.Position.CommitPosition,
_sequence++,
re.Event.Created,
evt,
Options.MetadataSerializer.DeserializeMeta(
Options,
re.Event.Metadata,
re.OriginalStreamId,
re.Event.EventStreamId,
re.Event.EventNumber
),
SubscriptionId,
Expand Down
42 changes: 15 additions & 27 deletions src/Experimental/src/Eventuous.Spyglass/InsidePeek.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,11 @@ void Scan(Assembly assembly) {

var methods = (type as dynamic).DeclaredMethods as MethodInfo[];

AggregateInfos.Add(
new AggregateInfo(
type,
stateType,
methods!,
() => CreateInstance(reg, type)
)
);
AggregateInfos.Add(new AggregateInfo(type, stateType, methods!, () => CreateInstance(reg, type)));
}

return;

Type? GetStateType(Type type)
=> type.BaseType!.GenericTypeArguments.Length == 0
? null
Expand All @@ -70,11 +65,9 @@ static dynamic CreateInstance(IReadOnlyDictionary<Type, Func<Aggregate>> reg, Ty
}

public async Task<object> Load(string streamName, int version) {
var typeName = streamName[..streamName.IndexOf('-')];
var agg = AggregateInfos.First(x => x.AggregateType == typeName);

var events = await _eventStore.ReadStream(new StreamName(streamName), StreamReadPosition.Start, true, CancellationToken.None);

var typeName = streamName[..streamName.IndexOf('-')];
var agg = AggregateInfos.First(x => x.AggregateType == typeName);
var events = await _eventStore.ReadStream(new StreamName(streamName), StreamReadPosition.Start, true, CancellationToken.None);
var aggregate = agg.GetAggregate();
var selectedEvents = version == -1 ? events : events.Take(version + 1);
aggregate.Load(selectedEvents.Select(x => x.Payload));
Expand Down Expand Up @@ -103,20 +96,16 @@ public AggregateInfo(Type aggregateType, Type stateType, MethodInfo[] methods, F
_factory = factory;
}

public dynamic GetAggregate()
=> _factory();
public dynamic GetAggregate() => _factory();

public object GetInfo() {
var instance = GetAggregate();
object state = instance.State;
var handlers = state.GetPrivateMember("_handlers");

var handlerType = typeof(Func<,,>).MakeGenericType(_stateType, typeof(object), _stateType);
var handlersDicType = typeof(Dictionary<,>).MakeGenericType(typeof(Type), handlerType);

dynamic handlersDic = Convert.ChangeType(handlers, handlersDicType)!;

IEnumerable<Type> keys = handlersDic.Keys;
var instance = GetAggregate();
object state = instance.State;
var handlers = state.GetPrivateMember("_handlers");
var handlerType = typeof(Func<,,>).MakeGenericType(_stateType, typeof(object), _stateType);
var handlersDicType = typeof(Dictionary<,>).MakeGenericType(typeof(Type), handlerType);
dynamic handlersDic = Convert.ChangeType(handlers, handlersDicType)!;
IEnumerable<Type> keys = handlersDic.Keys;

return new {
Type = _aggregateType.Name,
Expand All @@ -126,8 +115,7 @@ public object GetInfo() {
};
}

public override string ToString()
=> $"{_aggregateType.Name} ({_stateType.Name})";
public override string ToString() => $"{_aggregateType.Name} ({_stateType.Name})";

readonly Type _aggregateType;
readonly Type _stateType;
Expand Down
56 changes: 30 additions & 26 deletions src/Experimental/src/Eventuous.Spyglass/SpyglassApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
Expand All @@ -14,45 +13,50 @@ namespace Eventuous.Spyglass;

public static class SpyglassApi {
[PublicAPI]
public static IApplicationBuilder MapEventuousSpyglass(this IApplicationBuilder app, string? key = null) {
public static IApplicationBuilder MapEventuousSpyglass(this IApplicationBuilder app, string? key = null) {
var logger = app.ApplicationServices.GetRequiredService<ILogger<IApplicationBuilder>>();

if (!app.ApplicationServices.GetRequiredService<IWebHostEnvironment>().IsDevelopment() && key == null) {
logger.LogWarning("Insecure Spyglass API is only available in development environment");
key = Guid.NewGuid().ToString("N");
logger.LogInformation("Using generated key: {Key}", key);
}

if (key == null) {
logger.LogWarning("Spyglass API is not secured, ensure that it's not exposed to the Internet");
}

app.UseRouting();
app.UseEndpoints(builder =>
{
builder.MapGet("/spyglass/ping", (HttpRequest request) => CheckAndReturn(request, () => "Okay"))
.ExcludeFromDescription();

builder.MapGet(
"/spyglass/aggregates",
(HttpRequest request, [FromServices] InsidePeek peek) => CheckAndReturn(request, () => peek.Aggregates)
)
.ExcludeFromDescription();
app.UseEndpoints(
builder => {
builder.MapGet("/spyglass/ping", (HttpRequest request) => CheckAndReturn(request, () => "Okay"))
.ExcludeFromDescription();

builder.MapGet(
"/spyglass/aggregates",
(HttpRequest request, [FromServices] InsidePeek peek) => CheckAndReturn(request, () => peek.Aggregates)
)
.ExcludeFromDescription();

builder.MapGet(
"/spyglass/events",
(HttpRequest request, [FromServices] TypeMapper? typeMapper) => {
var typeMap = typeMapper ?? TypeMap.Instance;

builder.MapGet(
"/spyglass/events",
(HttpRequest request, [FromServices] TypeMapper? typeMapper) => {
var typeMap = typeMapper ?? TypeMap.Instance;
return CheckAndReturn(request, () => typeMap.ReverseMap.Select(x => x.Key));
}
)
.ExcludeFromDescription();
return CheckAndReturn(request, () => typeMap.ReverseMap.Select(x => x.Key));
}
)
.ExcludeFromDescription();

builder.MapGet(
"/spyglass/load/{streamName}",
(HttpRequest request, [FromServices] InsidePeek peek, string streamName, [FromQuery] int version)
=> CheckAndReturnAsync(request, () => peek.Load(streamName, version))
)
.ExcludeFromDescription();
});
builder.MapGet(
"/spyglass/load/{streamName}",
(HttpRequest request, [FromServices] InsidePeek peek, string streamName, [FromQuery] int version)
=> CheckAndReturnAsync(request, () => peek.Load(streamName, version))
)
.ExcludeFromDescription();
}
);

return app;

Expand Down