|
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.IO; |
4 | 4 | using System.Linq; |
| 5 | +using System.Reflection; |
5 | 6 | using System.Threading.Tasks; |
6 | 7 | using MessagePack; |
7 | 8 | using NebulaStore.Storage; |
@@ -212,10 +213,126 @@ private static IBlobStoreConnector CreateConnector(IEmbeddedStorageConfiguration |
212 | 213 | "blobstore" => new LocalBlobStoreConnector( |
213 | 214 | configuration.AfsConnectionString ?? configuration.StorageDirectory, |
214 | 215 | configuration.AfsUseCache), |
| 216 | + "firestore" => CreateFirestoreConnector(configuration), |
| 217 | + "azure.storage" => CreateAzureStorageConnector(configuration), |
| 218 | + "s3" => CreateS3Connector(configuration), |
215 | 219 | _ => throw new NotSupportedException($"AFS storage type '{configuration.AfsStorageType}' is not supported") |
216 | 220 | }; |
217 | 221 | } |
218 | 222 |
|
| 223 | + /// <summary> |
| 224 | + /// Creates a Google Cloud Firestore connector. |
| 225 | + /// </summary> |
| 226 | + /// <param name="configuration">The storage configuration</param> |
| 227 | + /// <returns>The Firestore connector</returns> |
| 228 | + private static IBlobStoreConnector CreateFirestoreConnector(IEmbeddedStorageConfiguration configuration) |
| 229 | + { |
| 230 | + try |
| 231 | + { |
| 232 | + // Use reflection to avoid hard dependency on Google Cloud Firestore |
| 233 | + var firestoreAssembly = System.Reflection.Assembly.LoadFrom("NebulaStore.Afs.GoogleCloud.Firestore.dll"); |
| 234 | + var connectorType = firestoreAssembly.GetType("NebulaStore.Afs.GoogleCloud.Firestore.GoogleCloudFirestoreConnector"); |
| 235 | + |
| 236 | + if (connectorType == null) |
| 237 | + throw new TypeLoadException("GoogleCloudFirestoreConnector type not found"); |
| 238 | + |
| 239 | + // Create FirestoreDb instance |
| 240 | + var firestoreDbType = Type.GetType("Google.Cloud.Firestore.FirestoreDb, Google.Cloud.Firestore"); |
| 241 | + if (firestoreDbType == null) |
| 242 | + throw new TypeLoadException("Google.Cloud.Firestore.FirestoreDb type not found. Make sure Google.Cloud.Firestore package is installed."); |
| 243 | + |
| 244 | + var createMethod = firestoreDbType.GetMethod("Create", new[] { typeof(string) }); |
| 245 | + if (createMethod == null) |
| 246 | + throw new MethodAccessException("FirestoreDb.Create method not found"); |
| 247 | + |
| 248 | + var projectId = configuration.AfsConnectionString ?? throw new ArgumentException("Project ID must be specified in AfsConnectionString for Firestore storage"); |
| 249 | + var firestoreDb = createMethod.Invoke(null, new object[] { projectId }); |
| 250 | + |
| 251 | + // Create connector |
| 252 | + var factoryMethod = configuration.AfsUseCache |
| 253 | + ? connectorType.GetMethod("Caching", new[] { firestoreDbType }) |
| 254 | + : connectorType.GetMethod("New", new[] { firestoreDbType }); |
| 255 | + |
| 256 | + if (factoryMethod == null) |
| 257 | + throw new MethodAccessException($"GoogleCloudFirestoreConnector factory method not found"); |
| 258 | + |
| 259 | + var connector = factoryMethod.Invoke(null, new[] { firestoreDb }); |
| 260 | + return (IBlobStoreConnector)connector!; |
| 261 | + } |
| 262 | + catch (Exception ex) when (!(ex is ArgumentException)) |
| 263 | + { |
| 264 | + throw new NotSupportedException( |
| 265 | + "Google Cloud Firestore connector could not be created. " + |
| 266 | + "Make sure NebulaStore.Afs.GoogleCloud.Firestore and Google.Cloud.Firestore packages are installed.", ex); |
| 267 | + } |
| 268 | + } |
| 269 | + |
| 270 | + /// <summary> |
| 271 | + /// Creates an Azure Storage connector. |
| 272 | + /// </summary> |
| 273 | + /// <param name="configuration">The storage configuration</param> |
| 274 | + /// <returns>The Azure Storage connector</returns> |
| 275 | + private static IBlobStoreConnector CreateAzureStorageConnector(IEmbeddedStorageConfiguration configuration) |
| 276 | + { |
| 277 | + try |
| 278 | + { |
| 279 | + // Use reflection to avoid hard dependency on Azure Storage |
| 280 | + var azureAssembly = System.Reflection.Assembly.LoadFrom("NebulaStore.Afs.Azure.Storage.dll"); |
| 281 | + var connectorType = azureAssembly.GetType("NebulaStore.Afs.Azure.Storage.AzureStorageConnector"); |
| 282 | + |
| 283 | + if (connectorType == null) |
| 284 | + throw new TypeLoadException("AzureStorageConnector type not found"); |
| 285 | + |
| 286 | + var connectionString = configuration.AfsConnectionString ?? throw new ArgumentException("Connection string must be specified in AfsConnectionString for Azure storage"); |
| 287 | + |
| 288 | + var factoryMethod = connectorType.GetMethod("FromConnectionString", new[] { typeof(string), typeof(bool) }); |
| 289 | + if (factoryMethod == null) |
| 290 | + throw new MethodAccessException("AzureStorageConnector.FromConnectionString method not found"); |
| 291 | + |
| 292 | + var connector = factoryMethod.Invoke(null, new object[] { connectionString, configuration.AfsUseCache }); |
| 293 | + return (IBlobStoreConnector)connector!; |
| 294 | + } |
| 295 | + catch (Exception ex) when (!(ex is ArgumentException)) |
| 296 | + { |
| 297 | + throw new NotSupportedException( |
| 298 | + "Azure Storage connector could not be created. " + |
| 299 | + "Make sure NebulaStore.Afs.Azure.Storage and Azure.Storage.Blobs packages are installed.", ex); |
| 300 | + } |
| 301 | + } |
| 302 | + |
| 303 | + /// <summary> |
| 304 | + /// Creates an AWS S3 connector. |
| 305 | + /// </summary> |
| 306 | + /// <param name="configuration">The storage configuration</param> |
| 307 | + /// <returns>The S3 connector</returns> |
| 308 | + private static IBlobStoreConnector CreateS3Connector(IEmbeddedStorageConfiguration configuration) |
| 309 | + { |
| 310 | + try |
| 311 | + { |
| 312 | + // Use reflection to avoid hard dependency on AWS S3 |
| 313 | + var s3Assembly = System.Reflection.Assembly.LoadFrom("NebulaStore.Afs.Aws.S3.dll"); |
| 314 | + var connectorType = s3Assembly.GetType("NebulaStore.Afs.Aws.S3.AwsS3Connector"); |
| 315 | + |
| 316 | + if (connectorType == null) |
| 317 | + throw new TypeLoadException("AwsS3Connector type not found"); |
| 318 | + |
| 319 | + var bucketName = configuration.AfsConnectionString ?? throw new ArgumentException("Bucket name must be specified in AfsConnectionString for S3 storage"); |
| 320 | + |
| 321 | + var factoryMethod = connectorType.GetMethod("FromBucketName", new[] { typeof(string), typeof(bool) }); |
| 322 | + if (factoryMethod == null) |
| 323 | + throw new MethodAccessException("AwsS3Connector.FromBucketName method not found"); |
| 324 | + |
| 325 | + var connector = factoryMethod.Invoke(null, new object[] { bucketName, configuration.AfsUseCache }); |
| 326 | + return (IBlobStoreConnector)connector!; |
| 327 | + } |
| 328 | + catch (Exception ex) when (!(ex is ArgumentException)) |
| 329 | + { |
| 330 | + throw new NotSupportedException( |
| 331 | + "AWS S3 connector could not be created. " + |
| 332 | + "Make sure NebulaStore.Afs.Aws.S3 and AWSSDK.S3 packages are installed.", ex); |
| 333 | + } |
| 334 | + } |
| 335 | + |
219 | 336 | /// <summary> |
220 | 337 | /// Registers type handlers for GigaMap serialization. |
221 | 338 | /// This enables automatic persistence of GigaMap instances following Eclipse Store patterns. |
|
0 commit comments