1
+ namespace Skyline . DataMiner . Sdk . CatalogService
2
+ {
3
+ using System ;
4
+ using System . IO ;
5
+ using System . Net ;
6
+ using System . Net . Http ;
7
+ using System . Net . Http . Headers ;
8
+ using System . Security . Authentication ;
9
+ using System . Threading ;
10
+ using System . Threading . Tasks ;
11
+
12
+ using Newtonsoft . Json ;
13
+
14
+ internal sealed class HttpCatalogService : ICatalogService , IDisposable
15
+ {
16
+ /// <summary>
17
+ /// Artifact information returned from uploading an artifact to the catalog using the non-volatile upload.
18
+ /// </summary>
19
+ private sealed class CatalogUploadResult
20
+ {
21
+ [ JsonProperty ( "catalogId" ) ]
22
+ public string CatalogId { get ; set ; }
23
+
24
+ [ JsonProperty ( "catalogVersionNumber" ) ]
25
+ public string CatalogVersionNumber { get ; set ; }
26
+
27
+ [ JsonProperty ( "azureStorageId" ) ]
28
+ public string AzureStorageId { get ; set ; }
29
+ }
30
+
31
+ /// <summary>
32
+ /// Artifact information returned from registering an artifact to the catalog.
33
+ /// </summary>
34
+ private sealed class CatalogRegisterResult
35
+ {
36
+ [ JsonProperty ( "catalogId" ) ]
37
+ public string CatalogId { get ; set ; }
38
+ }
39
+
40
+ /// <summary>
41
+ /// Represents an exception that is thrown when a version already exists.
42
+ /// </summary>
43
+ internal sealed class VersionAlreadyExistsException : Exception
44
+ {
45
+ /// <summary>
46
+ /// Gets the version that caused the exception.
47
+ /// </summary>
48
+ public string Version { get ; }
49
+
50
+ /// <summary>
51
+ /// Initializes a new instance of the <see cref="VersionAlreadyExistsException"/> class.
52
+ /// </summary>
53
+ public VersionAlreadyExistsException ( )
54
+ : base ( "The specified version already exists." )
55
+ {
56
+ }
57
+
58
+ /// <summary>
59
+ /// Initializes a new instance of the <see cref="VersionAlreadyExistsException"/> class
60
+ /// with a specified error message.
61
+ /// </summary>
62
+ /// <param name="version">The conflicting version.</param>
63
+ public VersionAlreadyExistsException ( string version )
64
+ : base ( $ "The specified version '{ version } ' already exists.")
65
+ {
66
+ Version = version ;
67
+ }
68
+
69
+ /// <summary>
70
+ /// Initializes a new instance of the <see cref="VersionAlreadyExistsException"/> class
71
+ /// with a specified error message and a reference to the inner exception that is the cause of this exception.
72
+ /// </summary>
73
+ /// <param name="version">The conflicting version.</param>
74
+ /// <param name="innerException">The exception that is the cause of the current exception.</param>
75
+ public VersionAlreadyExistsException ( string version , Exception innerException )
76
+ : base ( $ "The specified version '{ version } ' already exists.")
77
+ {
78
+ Version = version ;
79
+ }
80
+ }
81
+
82
+ private const string RegistrationPath = "api/key-catalog/v2-0/catalogs/register" ;
83
+ private const string VersionUploadPathEnd = "/register/version" ;
84
+ private const string VersionUploadPathStart = "api/key-catalog/v2-0/catalogs/" ;
85
+ private readonly HttpClient _httpClient ;
86
+
87
+ public HttpCatalogService ( HttpClient httpClient )
88
+ {
89
+ _httpClient = httpClient ;
90
+ }
91
+
92
+ public void Dispose ( )
93
+ {
94
+ _httpClient . Dispose ( ) ;
95
+ }
96
+
97
+ public async Task < ArtifactUploadResult > RegisterCatalogAsync ( byte [ ] catalogDetailsZip , string key , CancellationToken cancellationToken )
98
+ {
99
+ using ( var formData = new MultipartFormDataContent ( ) )
100
+ {
101
+ formData . Headers . Add ( "Ocp-Apim-Subscription-Key" , key ) ;
102
+
103
+ // Add file
104
+ using ( MemoryStream ms = new MemoryStream ( catalogDetailsZip ) )
105
+ {
106
+ ms . Write ( catalogDetailsZip , 0 , catalogDetailsZip . Length ) ;
107
+ ms . Position = 0 ;
108
+ formData . Add ( new StreamContent ( ms ) , "file" , "catalogDetails.zip" ) ;
109
+
110
+ // Make PUT request
111
+ var response = await _httpClient . PutAsync ( RegistrationPath , formData , cancellationToken ) . ConfigureAwait ( false ) ;
112
+
113
+ // Get the response body
114
+ var body = await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
115
+
116
+ if ( response . IsSuccessStatusCode )
117
+ {
118
+ var returnedResult = JsonConvert . DeserializeObject < CatalogRegisterResult > ( await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ) ;
119
+ return new ArtifactUploadResult { ArtifactId = returnedResult . CatalogId } ;
120
+ }
121
+
122
+ if ( response . StatusCode is HttpStatusCode . Forbidden || response . StatusCode is HttpStatusCode . Unauthorized )
123
+ {
124
+ throw new AuthenticationException ( $ "The registration api returned a { response . StatusCode } response. Body: { body } ") ;
125
+ }
126
+
127
+ throw new InvalidOperationException ( $ "The registration api returned a { response . StatusCode } response. Body: { body } ") ;
128
+ }
129
+ }
130
+ }
131
+
132
+ public Task < ArtifactUploadResult > UploadVersionAsync ( byte [ ] package , string fileName , string key , string catalogId , string version , string description , CancellationToken cancellationToken )
133
+ {
134
+ if ( String . IsNullOrWhiteSpace ( fileName ) ) throw new ArgumentNullException ( nameof ( fileName ) ) ;
135
+ if ( String . IsNullOrWhiteSpace ( key ) ) throw new ArgumentNullException ( nameof ( key ) ) ;
136
+ if ( String . IsNullOrWhiteSpace ( catalogId ) ) throw new ArgumentNullException ( nameof ( catalogId ) ) ;
137
+ if ( String . IsNullOrWhiteSpace ( version ) ) throw new ArgumentNullException ( nameof ( version ) ) ;
138
+
139
+ return UploadVersionInternalAsync ( package , fileName , key , catalogId , version , description , cancellationToken ) ;
140
+ }
141
+
142
+ private async Task < ArtifactUploadResult > UploadVersionInternalAsync ( byte [ ] package , string fileName , string key , string catalogId , string version , string description , CancellationToken cancellationToken )
143
+ {
144
+ string versionUploadPath = $ "{ VersionUploadPathStart } { catalogId } { VersionUploadPathEnd } ";
145
+ using ( var formData = new MultipartFormDataContent ( ) )
146
+ {
147
+ formData . Headers . Add ( "Ocp-Apim-Subscription-Key" , key ) ;
148
+
149
+ // Add the package (zip file) to the form data
150
+ using ( MemoryStream ms = new MemoryStream ( package ) )
151
+ {
152
+ ms . Position = 0 ; // Reset the stream position after writing
153
+
154
+ // Set up StreamContent with correct headers for the file
155
+ var fileContent = new StreamContent ( ms ) ;
156
+
157
+ fileContent . Headers . ContentDisposition = new ContentDispositionHeaderValue ( "form-data" )
158
+ {
159
+ Name = "\" file\" " ,
160
+ FileName = "\" " + fileName + "\" "
161
+ } ;
162
+ formData . Add ( fileContent ) ;
163
+
164
+ // Add version information to the form data
165
+ formData . Add ( new StringContent ( version ) , "versionNumber" ) ;
166
+ formData . Add ( new StringContent ( description ) , "versionDescription" ) ;
167
+
168
+ // Make the HTTP POST request
169
+ var response = await _httpClient . PostAsync ( versionUploadPath , formData , cancellationToken ) . ConfigureAwait ( false ) ;
170
+
171
+ // Read and log the response body
172
+ var body = await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
173
+
174
+ if ( response . IsSuccessStatusCode )
175
+ {
176
+ var returnedResult = JsonConvert . DeserializeObject < CatalogUploadResult > ( await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ) ;
177
+ return new ArtifactUploadResult { ArtifactId = returnedResult . AzureStorageId } ;
178
+ }
179
+
180
+ if ( response . StatusCode is HttpStatusCode . Forbidden || response . StatusCode is HttpStatusCode . Unauthorized )
181
+ {
182
+ throw new AuthenticationException ( $ "The version upload api returned a { response . StatusCode } response. Body: { body } ") ;
183
+ }
184
+
185
+ if ( response . StatusCode is HttpStatusCode . Conflict && body . Contains ( "already exists." ) )
186
+ {
187
+ throw new VersionAlreadyExistsException ( version ) ;
188
+ }
189
+
190
+ throw new InvalidOperationException ( $ "The version upload api returned a { response . StatusCode } response. Body: { body } ") ;
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
0 commit comments