tools/code/common/Subscription.cs (190 lines of code) (raw):
using Azure.Core.Pipeline;
using Flurl;
using LanguageExt;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace common;
public sealed record SubscriptionName : ResourceName, IResourceName<SubscriptionName>
{
private SubscriptionName(string value) : base(value) { }
public static SubscriptionName From(string value) => new(value);
}
public sealed record SubscriptionsUri : ResourceUri
{
public required ManagementServiceUri ServiceUri { get; init; }
private static string PathSegment { get; } = "subscriptions";
protected override Uri Value => ServiceUri.ToUri().AppendPathSegment(PathSegment).ToUri();
public static SubscriptionsUri From(ManagementServiceUri serviceUri) =>
new() { ServiceUri = serviceUri };
}
public sealed record SubscriptionUri : ResourceUri
{
public required SubscriptionsUri Parent { get; init; }
public required SubscriptionName Name { get; init; }
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
public static SubscriptionUri From(SubscriptionName name, ManagementServiceUri serviceUri) =>
new()
{
Parent = SubscriptionsUri.From(serviceUri),
Name = name
};
}
public sealed record SubscriptionsDirectory : ResourceDirectory
{
public required ManagementServiceDirectory ServiceDirectory { get; init; }
private static string Name { get; } = "subscriptions";
protected override DirectoryInfo Value =>
ServiceDirectory.ToDirectoryInfo().GetChildDirectory(Name);
public static SubscriptionsDirectory From(ManagementServiceDirectory serviceDirectory) =>
new() { ServiceDirectory = serviceDirectory };
public static Option<SubscriptionsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
directory is not null &&
directory.Name == Name &&
directory.Parent?.FullName == serviceDirectory.ToDirectoryInfo().FullName
? new SubscriptionsDirectory { ServiceDirectory = serviceDirectory }
: Option<SubscriptionsDirectory>.None;
}
public sealed record SubscriptionDirectory : ResourceDirectory
{
public required SubscriptionsDirectory Parent { get; init; }
public required SubscriptionName Name { get; init; }
protected override DirectoryInfo Value =>
Parent.ToDirectoryInfo().GetChildDirectory(Name.Value);
public static SubscriptionDirectory From(SubscriptionName name, ManagementServiceDirectory serviceDirectory) =>
new()
{
Parent = SubscriptionsDirectory.From(serviceDirectory),
Name = name
};
public static Option<SubscriptionDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
from parent in SubscriptionsDirectory.TryParse(directory?.Parent, serviceDirectory)
select new SubscriptionDirectory
{
Parent = parent,
Name = SubscriptionName.From(directory!.Name)
};
}
public sealed record SubscriptionInformationFile : ResourceFile
{
public required SubscriptionDirectory Parent { get; init; }
public static string Name { get; } = "subscriptionInformation.json";
protected override FileInfo Value =>
Parent.ToDirectoryInfo().GetChildFile(Name);
public static SubscriptionInformationFile From(SubscriptionName name, ManagementServiceDirectory serviceDirectory) =>
new()
{
Parent = SubscriptionDirectory.From(name, serviceDirectory)
};
public static Option<SubscriptionInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
file is not null &&
file.Name == Name
? from parent in SubscriptionDirectory.TryParse(file.Directory, serviceDirectory)
select From(parent.Name, serviceDirectory)
: Option<SubscriptionInformationFile>.None;
}
public sealed record SubscriptionDto
{
[JsonPropertyName("properties")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public required SubscriptionContract Properties { get; init; }
public sealed record SubscriptionContract
{
[JsonPropertyName("displayName")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string? DisplayName { get; init; }
[JsonPropertyName("scope")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string? Scope { get; init; }
[JsonPropertyName("allowTracing")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public bool? AllowTracing { get; init; }
[JsonPropertyName("ownerId")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string? OwnerId { get; init; }
[JsonPropertyName("primaryKey")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string? PrimaryKey { get; init; }
[JsonPropertyName("secondaryKey")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string? SecondaryKey { get; init; }
[JsonPropertyName("state")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string? State { get; init; }
}
}
public static class SubscriptionModule
{
public static async ValueTask DeleteAll(this SubscriptionsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
await uri.ListNames(pipeline, cancellationToken)
.IterParallel(async name =>
{
var resourceUri = SubscriptionUri.From(name, uri.ServiceUri);
await resourceUri.Delete(pipeline, cancellationToken);
}, cancellationToken);
public static IAsyncEnumerable<SubscriptionName> ListNames(this SubscriptionsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
.Select(jsonObject => jsonObject.GetStringProperty("name"))
.Select(SubscriptionName.From);
public static IAsyncEnumerable<(SubscriptionName Name, SubscriptionDto Dto)> List(this SubscriptionsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
uri.ListNames(pipeline, cancellationToken)
.SelectAwait(async name =>
{
var resourceUri = new SubscriptionUri { Parent = uri, Name = name };
var dto = await resourceUri.GetDto(pipeline, cancellationToken);
return (name, dto);
});
public static async ValueTask<Option<SubscriptionDto>> TryGetDto(this SubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
{
var contentOption = await pipeline.GetContentOption(uri.ToUri(), cancellationToken);
return contentOption.Map(content => content.ToObjectFromJson<SubscriptionDto>());
}
public static async ValueTask<SubscriptionDto> GetDto(this SubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
{
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
return content.ToObjectFromJson<SubscriptionDto>();
}
public static async ValueTask Delete(this SubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
public static async ValueTask PutDto(this SubscriptionUri uri, SubscriptionDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
{
var content = BinaryData.FromObjectAsJson(dto);
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
}
public static IEnumerable<SubscriptionDirectory> ListDirectories(ManagementServiceDirectory serviceDirectory)
{
var subscriptionsDirectory = SubscriptionsDirectory.From(serviceDirectory);
return subscriptionsDirectory.ToDirectoryInfo()
.ListDirectories("*")
.Select(directoryInfo => SubscriptionName.From(directoryInfo.Name))
.Select(name => new SubscriptionDirectory { Parent = subscriptionsDirectory, Name = name });
}
public static IEnumerable<SubscriptionInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) =>
ListDirectories(serviceDirectory)
.Select(directory => new SubscriptionInformationFile { Parent = directory })
.Where(informationFile => informationFile.ToFileInfo().Exists());
public static async ValueTask WriteDto(this SubscriptionInformationFile file, SubscriptionDto dto, CancellationToken cancellationToken)
{
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
}
public static async ValueTask<SubscriptionDto> ReadDto(this SubscriptionInformationFile file, CancellationToken cancellationToken)
{
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
return content.ToObjectFromJson<SubscriptionDto>();
}
public static Option<ApiName> TryGetApiName(SubscriptionDto dto) =>
from scope in Prelude.Optional(dto.Properties.Scope)
where scope.Contains("/apis/", StringComparison.OrdinalIgnoreCase)
from apiNameString in scope.Split('/').LastOrNone()
select ApiName.From(apiNameString);
public static Option<ProductName> TryGetProductName(SubscriptionDto dto) =>
from scope in Prelude.Optional(dto.Properties.Scope)
where scope.Contains("/products/", StringComparison.OrdinalIgnoreCase)
from productNameString in scope.Split('/').LastOrNone()
select ProductName.From(productNameString);
}