This repository was archived by the owner on Mar 31, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathPackageFileService.cs
More file actions
215 lines (180 loc) · 7.42 KB
/
PackageFileService.cs
File metadata and controls
215 lines (180 loc) · 7.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Security.Cryptography.Pkcs;
using CommunityToolkit.HighPerformance;
using Knapcode.MiniZip;
using MessagePack;
using NuGet.Packaging.Signing;
#nullable enable
namespace NuGet.Insights
{
public class PackageFileService
{
private readonly ContainerInitializationState _initializationState;
private readonly PackageWideEntityService _wideEntityService;
private readonly FlatContainerClient _flatContainerClient;
private readonly FileDownloader _fileDownloader;
private readonly MZipFormat _mzipFormat;
private readonly IOptions<NuGetInsightsSettings> _options;
private readonly ILogger<PackageFileService> _logger;
public PackageFileService(
PackageWideEntityService wideEntityService,
FlatContainerClient flatContainerClient,
FileDownloader fileDownloader,
MZipFormat mzipFormat,
IOptions<NuGetInsightsSettings> options,
ILogger<PackageFileService> logger)
{
_initializationState = ContainerInitializationState.New(InitializeInternalAsync, DestroyInternalAsync);
_wideEntityService = wideEntityService;
_flatContainerClient = flatContainerClient;
_fileDownloader = fileDownloader;
_mzipFormat = mzipFormat;
_options = options;
_logger = logger;
}
public async Task InitializeAsync()
{
await _initializationState.InitializeAsync();
}
public async Task DestroyAsync()
{
await _initializationState.DestroyAsync();
}
private async Task InitializeInternalAsync()
{
await _wideEntityService.InitializeAsync(_options.Value.PackageArchiveTableName);
}
private async Task DestroyInternalAsync()
{
await _wideEntityService.DeleteTableAsync(_options.Value.PackageArchiveTableName);
}
public async Task<PrimarySignature?> GetPrimarySignatureAsync(IPackageIdentityCommit leafItem)
{
var info = await GetOrUpdateInfoFromLeafItemAsync(leafItem);
if (!info.Available)
{
return null;
}
using var srcStream = info.SignatureBytes.AsStream();
return PrimarySignature.Load(srcStream);
}
public async Task<ZipDirectory?> GetZipDirectoryAsync(IPackageIdentityCommit leafItem)
{
var info = await GetZipDirectoryAndLengthAsync(leafItem);
return info?.Directory;
}
public async Task<(ZipDirectory Directory, long Length, ILookup<string, string> Headers)?> GetZipDirectoryAndLengthAsync(IPackageIdentityCommit leafItem)
{
var info = await GetOrUpdateInfoFromLeafItemAsync(leafItem);
if (!info.Available)
{
return null;
}
using var srcStream = info.MZipBytes.AsStream();
using var destStream = await _mzipFormat.ReadAsync(srcStream);
var reader = new ZipDirectoryReader(destStream);
return (await reader.ReadAsync(), destStream.Length, info.HttpHeaders!);
}
public async Task<IReadOnlyDictionary<IPackageIdentityCommit, PackageFileInfoV1>> UpdateBatchAsync(string id, IReadOnlyCollection<IPackageIdentityCommit> leafItems)
{
return await _wideEntityService.UpdateBatchAsync(
_options.Value.PackageArchiveTableName,
id,
leafItems,
GetInfoAsync,
OutputToData,
DataToOutput);
}
public async Task<PackageFileInfoV1> GetOrUpdateInfoFromLeafItemAsync(IPackageIdentityCommit leafItem)
{
return await _wideEntityService.GetOrUpdateInfoAsync(
_options.Value.PackageArchiveTableName,
leafItem,
GetInfoAsync,
OutputToData,
DataToOutput);
}
private async Task<PackageFileInfoV1> GetInfoAsync(IPackageIdentityCommit leafItem)
{
if (leafItem.LeafType == CatalogLeafType.PackageDelete)
{
return MakeDeletedInfo(leafItem);
}
var url = await _flatContainerClient.GetPackageContentUrlAsync(leafItem.PackageId, leafItem.PackageVersion);
using var reader = await _fileDownloader.GetZipDirectoryReaderAsync(
leafItem.PackageId,
leafItem.PackageVersion,
ArtifactFileType.Nupkg,
url);
if (reader is null)
{
return MakeDeletedInfo(leafItem);
}
return await GetInfoAsync(leafItem, reader.Properties, reader, url);
}
private async Task<PackageFileInfoV1> GetInfoAsync(
IPackageIdentityCommit leafItem,
ILookup<string, string> headers,
ZipDirectoryReader reader,
string url)
{
var zipDirectory = await reader.ReadAsync();
var signatureBytes = await _fileDownloader.GetSignatureBytesAsync(reader, zipDirectory, leafItem.PackageId, leafItem.PackageVersion, url);
var signedCms = new SignedCms();
signedCms.Decode(signatureBytes);
using var destStream = new MemoryStream();
await _mzipFormat.WriteAsync(reader.Stream, destStream);
return new PackageFileInfoV1
{
CommitTimestamp = leafItem.CommitTimestamp,
Available = true,
HttpHeaders = headers,
MZipBytes = new Memory<byte>(destStream.GetBuffer(), 0, (int)destStream.Length),
SignatureBytes = signatureBytes.AsMemory(),
};
}
private static PackageFileInfoV1 MakeDeletedInfo(IPackageIdentityCommit leafItem)
{
return new PackageFileInfoV1
{
CommitTimestamp = leafItem.CommitTimestamp,
Available = false,
};
}
private static PackageFileInfoV1 DataToOutput(PackageFileInfoVersions data)
{
return data.V1;
}
private static PackageFileInfoVersions OutputToData(PackageFileInfoV1 output)
{
return new PackageFileInfoVersions(output);
}
[MessagePackObject]
public class PackageFileInfoVersions : PackageWideEntityService.IPackageWideEntity
{
[SerializationConstructor]
public PackageFileInfoVersions(PackageFileInfoV1 v1)
{
V1 = v1;
}
[Key(0)]
public PackageFileInfoV1 V1 { get; set; }
DateTimeOffset? PackageWideEntityService.IPackageWideEntity.CommitTimestamp => V1.CommitTimestamp;
}
[MessagePackObject]
public class PackageFileInfoV1
{
[Key(1)]
public DateTimeOffset? CommitTimestamp { get; set; }
[Key(2)]
public bool Available { get; set; }
[Key(3)]
public ILookup<string, string>? HttpHeaders { get; set; }
[Key(4)]
public Memory<byte> MZipBytes { get; set; }
[Key(5)]
public Memory<byte> SignatureBytes { get; set; }
}
}
}