The storage layer is built as a hierarchy of interfaces and implementations. Low-level blob operations are separated from domain-level archive operations, and encryption with compression is added as a decorator rather than baked into any single class.
Interface and class hierarchy
| Type | Kind | Role |
|---|
IStorage | Interface | Low-level blob storage primitives (container and stream operations) |
AzureBlobStorage | Class | Concrete IStorage backed by Azure Blob Storage |
IArchiveStorage | Interface | Domain-level archive operations: hashes, compression levels, storage tiers |
EncryptedCompressedStorage | Class | Concrete IArchiveStorage that wraps any IStorage with AES256 encryption and GZip compression |
Relationships
IStorage
└── AzureBlobStorage
(accountName, accountKey, containerName)
IArchiveStorage
└── EncryptedCompressedStorage
(IStorage, passphrase)
└── delegates to ──▶ IStorage
EncryptedCompressedStorage holds a reference to IStorage and delegates every actual network call to it. This means the encryption/compression layer is independent of which storage backend is in use — AzureBlobStorage can be swapped for a test double without changing any archival logic.
IStorage
IStorage defines the lowest-level contract: basic container and stream operations with no domain concepts. It provides the fundamental primitives that any storage backend must support.
IStorage has no knowledge of hashes, compression levels, or storage tiers. Those concerns belong to IArchiveStorage.
AzureBlobStorage
new AzureBlobStorage(accountName, accountKey, containerName)
AzureBlobStorage is the production implementation of IStorage. It handles:
- Authentication — uses
accountName and accountKey to authenticate against the Azure Storage service.
- Container management — targets the specified
containerName for all operations.
- Blob operations — read, write, list, and manage blobs through the
Azure.Storage.Blobs SDK.
IArchiveStorage
IArchiveStorage operates at the domain level. It exposes operations in terms of Arius domain concepts:
- File content addressed by
Hash values.
- Configurable compression levels.
- Azure Blob Storage access tiers (Hot, Cool, Archive).
- Application state upload and download.
EncryptedCompressedStorage
new EncryptedCompressedStorage(IStorage storage, string passphrase)
EncryptedCompressedStorage implements IArchiveStorage and wraps any IStorage to add:
- GZip compression — applied before encryption so the plaintext is compressed before it becomes uncompressible ciphertext.
- AES256 encryption — client-side, using the supplied passphrase. Data is encrypted before it leaves the local machine.
The transformation applied to every piece of data written through this layer is:
Plaintext → GZip → AES256 → IStorage.Write()
Reads reverse the process:
IStorage.Read() → AES256 decrypt → GZip decompress → Plaintext
The passphrase is the sole key material for AES256 encryption. It is never stored and cannot be recovered. Losing the passphrase means the archived data cannot be decrypted.
HandlerContext integration
The HandlerContext for the archive and restore commands holds an IArchiveStorage reference (always a EncryptedCompressedStorage wrapping an AzureBlobStorage in production). Handlers never construct storage objects themselves — the HandlerContextBuilder does that during context initialisation.
HandlerContextBuilder
1. Creates AzureBlobStorage(accountName, accountKey, containerName)
2. Wraps it: EncryptedCompressedStorage(azureBlobStorage, passphrase)
3. Stores it: HandlerContext.ArchiveStorage = encryptedCompressedStorage
CommandHandler
└── context.ArchiveStorage.Upload(hash, stream, tier) ──▶ Azure Blob Storage
This means handlers are written against the IArchiveStorage interface and are unaware of whether data is going to Azure or a test stub.
In tests, EncryptedCompressedStorage can be constructed with an in-memory IStorage implementation to exercise the full encryption and compression path without any network calls.