Skip to content
Draft
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/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.18.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.18.0" />
<PackageVersion Include="Particular.Approvals" Version="2.0.1" />
<PackageVersion Include="Particular.LicensingComponent.Report" Version="1.4.0" />
<PackageVersion Include="Particular.LicensingComponent.Report" Version="1.5.0" />
<PackageVersion Include="Particular.Licensing.Sources" Version="7.4.0" />
<PackageVersion Include="Particular.Obsoletes" Version="1.1.0" />
<PackageVersion Include="Particular.ServicePulse.Core" Version="2.12.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,26 @@ public class Product

public record QueueIdentity
{
public string? NameHash { get; set; }
public required string NameHash { get; set; }
public string? ScopeHash { get; set; }
public string? OriginalLocation { get; set; }
}

public record LicensedEndpoint
{
public string? ClientId { get; set; }
public string? Name { get; set; }
public int? Classification { get; set; }
public string ClientId { get; set; } = Guid.NewGuid().ToString();
public required string Name { get; set; }
public required int Classification { get; set; }
public string? EndpointSize { get; set; }

public QueueIdentity[] Queues { get; set; } = [];
}

public class LicensedEndpointAmendment
{
public string? ClientId { get; set; }
public string? Name { get; set; }
public int? Classification { get; set; }
public required string ClientId { get; set; }
public required string Name { get; set; }
public required int Classification { get; set; }
public QueueIdentity[] AmendedQueues { get; set; } = [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ public Task SaveReportMasks(List<string> reportMasks, CancellationToken cancella
return Task.CompletedTask;
}

public Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(CancellationToken cancellationToken = default) => Task.FromResult(endpointDetails?.Amend(endpointDetailsAmendment));
public Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(bool amendWithUserChanges = true, CancellationToken cancellationToken = default) =>
Task.FromResult(amendWithUserChanges ? endpointDetails?.Amend(endpointDetailsAmendment) : endpointDetails);

public Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, CancellationToken cancellationToken = default)
{
Expand All @@ -185,9 +186,12 @@ public Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, Cancella
return Task.CompletedTask;
}

public Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment result, CancellationToken cancellationToken = default)
public Task<LicensedEndpointDetailsAmendment?> GetLicensedEndpointDetailsAmendments(CancellationToken cancellationToken = default) =>
Task.FromResult(endpointDetailsAmendment);

public Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment? result, CancellationToken cancellationToken = default)
{
result.UnmappedQueues = [.. endpointDetailsAmendment?.UnmappedQueues ?? [], .. result.UnmappedQueues];
result?.UnmappedQueues = [.. endpointDetailsAmendment?.UnmappedQueues ?? [], .. result.UnmappedQueues];
endpointDetailsAmendment = result;
return Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ Task RecordEndpointThroughput(string endpointName, ThroughputSource throughputSo
Task<List<string>> GetReportMasks(CancellationToken cancellationToken = default);
Task SaveReportMasks(List<string> reportMasks, CancellationToken cancellationToken = default);

Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(CancellationToken cancellationToken = default);
Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(bool amendWithUserChanges = true, CancellationToken cancellationToken = default);
Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, CancellationToken cancellationToken = default);
Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment result, CancellationToken cancellationToken = default);
Task<LicensedEndpointDetailsAmendment?> GetLicensedEndpointDetailsAmendments(CancellationToken cancellationToken = default);
Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment? result, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
Expand Up @@ -258,12 +258,13 @@ public Task<List<string>> GetReportMasks(CancellationToken cancellationToken = d
public Task SaveReportMasks(List<string> reportMasks, CancellationToken cancellationToken = default) =>
throw new NotSupportedException();

public Task<LicensedEndpointDetails> GetLicensedEndpointDetails(CancellationToken cancellationToken = default) =>
public Task<LicensedEndpointDetails> GetLicensedEndpointDetails(bool amendWithUserChanges = true, CancellationToken cancellationToken = default) =>
throw new NotSupportedException();

public Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public Task RemoveEndpoints(EndpointIdentifier[] endpointIds, CancellationToken cancellationToken = default) => throw new NotImplementedException();
public Task<LicensedEndpointDetailsAmendment> GetLicensedEndpointDetailsAmendments(CancellationToken cancellationToken = default) => throw new NotImplementedException();
public Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment result, CancellationToken cancellationToken = default) => throw new NotImplementedException();
}

Expand Down
30 changes: 29 additions & 1 deletion src/Particular.LicensingComponent/ThroughputCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ public async Task<SignedReport> GenerateThroughputReport(string spVersion, DateT

var auditServiceMetadata = await dataStore.GetAuditServiceMetadata(cancellationToken);
var brokerMetaData = await dataStore.GetBrokerMetadata(cancellationToken);
var endpointMetadata = await dataStore.GetLicensedEndpointDetails(false, cancellationToken);
var endpointMetadataAmendments = await dataStore.GetLicensedEndpointDetailsAmendments(cancellationToken);
var report = new Report.Report
{
EndTime = new DateTimeOffset((DateTime)reportEndDate, TimeSpan.Zero),
Expand All @@ -172,7 +174,33 @@ public async Task<SignedReport> GenerateThroughputReport(string spVersion, DateT
Queues = [.. queueThroughputs],
TotalQueues = queueThroughputs.Count,
// A copy, because the report adds its own keys. The data store can return a shared instance.
EnvironmentInformation = new EnvironmentInformation { AuditServicesData = new AuditServicesData(auditServiceMetadata.Versions, auditServiceMetadata.Transports), EnvironmentData = new Dictionary<string, string>(brokerMetaData.Data) }
EnvironmentInformation = new EnvironmentInformation { AuditServicesData = new AuditServicesData(auditServiceMetadata.Versions, auditServiceMetadata.Transports), EnvironmentData = new Dictionary<string, string>(brokerMetaData.Data) },
CustomerLicenseAmendments = (endpointMetadata, endpointMetadataAmendments) switch
{
(null, null) => null,
(_, null) => null,
(null, _) => null,
(LicensedEndpointDetails baseDetails, LicensedEndpointDetailsAmendment amendments) => new LicenseAmendments
{
ExcludedQueues = [.. amendments.ExcludedQueues.Select(qId => new Report.QueueIdentity { NameHash = qId.NameHash, ScopeHash = qId.ScopeHash })],
InfrastructureQueues = [.. amendments.InfrastructureQueues.Select(qId => new Report.QueueIdentity { NameHash = qId.NameHash, ScopeHash = qId.ScopeHash })],
RemovedEndpointNames = [.. baseDetails.Endpoints.Where(endpoint => endpointMetadataAmendments.RemovedEndpointIds.Contains(endpoint.ClientId)).Select(endpoint => endpoint.Name)],
Endpoints = [.. amendments.Endpoints.Select(amended => {
var previousEndpoint = baseDetails.Endpoints.FirstOrDefault(endpoint => endpoint.ClientId == amended.ClientId);
Contracts.QueueIdentity[] notThisEndpointQueues = [.. amendments.UnassignedQueues, .. amendments.ExcludedQueues, .. amendments.InfrastructureQueues, .. amendments.Endpoints.Where(endpoint => endpoint.ClientId != amended.ClientId).SelectMany(endpoint => endpoint.AmendedQueues)];
return new Report.LicensedEndpointAmendment
{
PreviousName = previousEndpoint?.Name,
PreviousNameHash = previousEndpoint is not null ? OneWayHasher.CalculateOneWayHash(previousEndpoint.Name) : null,
CurrentName = masker.Mask(amended.Name),
CurrentNameHash = OneWayHasher.CalculateOneWayHash(amended.Name),
IsSendOnly = amended.Classification == 1,
AmendedQueues = [.. amended.AmendedQueues.Select(qId => new Report.QueueIdentity { NameHash = qId.NameHash, ScopeHash = qId.ScopeHash })],
RemovedQueues = previousEndpoint is not null ? [.. previousEndpoint.Queues.Where(qId => notThisEndpointQueues.Contains(qId)).Select(qId => new Report.QueueIdentity { NameHash = qId.NameHash, ScopeHash = qId.ScopeHash })] : []
};
})]
},
}
};

var auditThroughput = queueThroughputs.SelectMany(w => w.DailyThroughputFromAudit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,16 +308,16 @@ public Task<List<string>> GetReportMasks(CancellationToken cancellationToken = d
public Task SaveReportMasks(List<string> reportMasks, CancellationToken cancellationToken = default) =>
ExecuteWithDbContext((context, token) => context.StoreSetting(SettingKeys.ReportMasks, reportMasks, token), cancellationToken);

public Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(CancellationToken cancellationToken = default) =>
public Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(bool amendWithUserChanges = true, CancellationToken cancellationToken = default) =>
ExecuteWithDbContext(async (context, token) =>
{
var baseDetails = await context.GetSetting<LicensedEndpointDetails>(SettingKeys.LicensedEndpointDetails, token);
if (baseDetails is null)
if (baseDetails is not null && amendWithUserChanges)
{
return null;
var amendments = await context.GetSetting<LicensedEndpointDetailsAmendment>(SettingKeys.LicensedEndpointDetailsAmendment, token);
return baseDetails.Amend(amendments);
}
var amendments = await context.GetSetting<LicensedEndpointDetailsAmendment>(SettingKeys.LicensedEndpointDetailsAmendment, token);
return baseDetails.Amend(amendments);
return baseDetails;
}, cancellationToken);

public Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, CancellationToken cancellationToken = default) =>
Expand All @@ -327,12 +327,21 @@ public Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, Cancella
await context.StoreSetting(SettingKeys.LicensedEndpointDetailsAmendment, new LicensedEndpointDetailsAmendment(), token);
}, cancellationToken);

public Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment result, CancellationToken cancellationToken = default) =>
public Task<LicensedEndpointDetailsAmendment?> GetLicensedEndpointDetailsAmendments(CancellationToken cancellationToken = default) =>
ExecuteWithDbContext((context, token) => context.GetSetting<LicensedEndpointDetailsAmendment>(SettingKeys.LicensedEndpointDetailsAmendment, token), cancellationToken);

public Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment? result, CancellationToken cancellationToken = default) =>
ExecuteWithDbContext(async (context, token) =>
{
var existing = await context.GetSetting<LicensedEndpointDetailsAmendment>(SettingKeys.LicensedEndpointDetailsAmendment, token);
if (existing is not null)
{
if (result is null)
{
context.Remove(existing);
await context.SaveChangesAsync(cancellationToken);
return;
}
// these do not round-trip
result.UnmappedQueues = [.. existing.UnmappedQueues, .. result.UnmappedQueues];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,18 +338,18 @@ public async Task SaveReportMasks(List<string> reportMasks, CancellationToken ca
await session.SaveChangesAsync(cancellationToken);
}

public async Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(CancellationToken cancellationToken = default)
public async Task<LicensedEndpointDetails?> GetLicensedEndpointDetails(bool amendWithUserChanges = true, CancellationToken cancellationToken = default)
{
var store = await storeProvider.GetDocumentStore(cancellationToken);
using IAsyncDocumentSession session = store.OpenAsyncSession(databaseConfiguration.Name);

var baseDetails = await session.LoadAsync<LicensedEndpointDetails>(LicencedEndpointDetailsDocumentId, cancellationToken);
if (baseDetails is null)
if (baseDetails is not null && amendWithUserChanges)
{
return null;
var amendments = await session.LoadAsync<LicensedEndpointDetailsAmendment>(LicencedEndpointDetailsAmendmentDocumentId, cancellationToken);
return baseDetails.Amend(amendments);
}
var amendments = await session.LoadAsync<LicensedEndpointDetailsAmendment>(LicencedEndpointDetailsAmendmentDocumentId, cancellationToken);
return baseDetails.Amend(amendments);
return baseDetails;
}

public async Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, CancellationToken cancellationToken = default)
Expand All @@ -362,20 +362,36 @@ public async Task SaveLicensedEndpointDetails(LicensedEndpointDetails result, Ca
await session.SaveChangesAsync(cancellationToken);
}

public async Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment result, CancellationToken cancellationToken = default)
public async Task<LicensedEndpointDetailsAmendment?> GetLicensedEndpointDetailsAmendments(CancellationToken cancellationToken = default)
{
var store = await storeProvider.GetDocumentStore(cancellationToken);
using IAsyncDocumentSession session = store.OpenAsyncSession(databaseConfiguration.Name);

var existing = await session.LoadAsync<LicensedEndpointDetailsAmendment>(LicencedEndpointDetailsAmendmentDocumentId, cancellationToken);
if (existing is not null)
return await session.LoadAsync<LicensedEndpointDetailsAmendment>(LicencedEndpointDetailsAmendmentDocumentId, cancellationToken);
}

public async Task SaveLicensedEndpointDetailsAmendment(LicensedEndpointDetailsAmendment? result, CancellationToken cancellationToken = default)
{
var store = await storeProvider.GetDocumentStore(cancellationToken);
using IAsyncDocumentSession session = store.OpenAsyncSession(databaseConfiguration.Name);

if (result is null)
{
// these do not round-trip
result.UnmappedQueues = [.. existing.UnmappedQueues, .. result.UnmappedQueues];
session.Advanced.Evict(existing);
session.Delete(LicencedEndpointDetailsAmendmentDocumentId);
}
else
{
var existing = await session.LoadAsync<LicensedEndpointDetailsAmendment>(LicencedEndpointDetailsAmendmentDocumentId, cancellationToken);
if (existing is not null)
{
// these do not round-trip
result.UnmappedQueues = [.. existing.UnmappedQueues, .. result.UnmappedQueues];
session.Advanced.Evict(existing);
}

await session.StoreAsync(result, LicencedEndpointDetailsAmendmentDocumentId, cancellationToken);
}

await session.StoreAsync(result, LicencedEndpointDetailsAmendmentDocumentId, cancellationToken);
await session.SaveChangesAsync(cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,14 @@ await LicensingDataStore.SaveLicensedEndpointDetails(new LicensedEndpointDetails
new LicensedEndpoint
{
ClientId = "endpoint-to-keep",
Name = "Endpoint to keep"
Name = "Endpoint to keep",
Classification = 0
},
new LicensedEndpoint
{
ClientId = "endpoint-to-remove",
Name = "Endpoint to remove"
Name = "Endpoint to remove",
Classification = 0
}
]
});
Expand Down Expand Up @@ -130,12 +132,14 @@ await LicensingDataStore.SaveLicensedEndpointDetails(new LicensedEndpointDetails
new LicensedEndpoint
{
ClientId = "first-endpoint",
Name = "First endpoint"
Name = "First endpoint",
Classification = 0
},
new LicensedEndpoint
{
ClientId = "second-endpoint",
Name = "Second endpoint"
Name = "Second endpoint",
Classification = 0
}
]
});
Expand Down Expand Up @@ -170,7 +174,8 @@ await LicensingDataStore.SaveLicensedEndpointDetails(new LicensedEndpointDetails
new LicensedEndpoint
{
ClientId = "endpoint-id",
Name = "Original name"
Name = "Original name",
Classification = 0
}
]
});
Expand All @@ -188,7 +193,8 @@ await LicensingDataStore.SaveLicensedEndpointDetails(new LicensedEndpointDetails
new LicensedEndpoint
{
ClientId = "endpoint-id",
Name = "Replacement name"
Name = "Replacement name",
Classification = 0
}
]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ GET /license => ServiceControl.Licensing.LicenseController:License(Boolean refre
POST /license/amendDetails => ServiceControl.Licensing.LicenseController:AmendLicenseDetails(LicensedEndpointDetailsAmendment amendment, CancellationToken cancellationToken)
GET /license/details => ServiceControl.Licensing.LicenseController:LicenseDetails(CancellationToken cancellationToken)
POST /license/detailsUpload => ServiceControl.Licensing.LicenseController:UploadLicenseDetails(IFormFile file, CancellationToken cancellationToken)
POST /license/removeAmendments => ServiceControl.Licensing.LicenseController:RemoveLicenseDetailsAmendments(CancellationToken cancellationToken)
GET /messages => ServiceControl.CompositeViews.Messages.GetMessagesController:Messages(PagingInfo pagingInfo, SortInfo sortInfo, Boolean includeSystemMessages, CancellationToken cancellationToken)
GET /messages/{id}/body => ServiceControl.CompositeViews.Messages.GetMessagesController:Get(String id, String instanceId, CancellationToken cancellationToken)
GET /messages/search => ServiceControl.CompositeViews.Messages.GetMessagesController:Search(PagingInfo pagingInfo, SortInfo sortInfo, String q, CancellationToken cancellationToken)
Expand Down
Loading
Loading