# Disk

## Description

For local development, single-node deployments, or simple on-prem scenarios, you can back `IFlexFileStore` with the local filesystem using `LocalFileStore`.

## Important concepts

* **`LocalFileStore` is a core implementation**: it lives in `Sumeru.Flex.Core` and does not require a cloud SDK.
* **Base path scoping**: all operations are relative to a configured `BasePath`.
* **Permissions matter**: the host process must have read/write access to the base directory.

## Configuration in DI

Unlike cloud providers, `LocalFileStore` is wired directly (there isn’t a generated `AddFlex...FileStore(...)` extension for it).

Add this in your DI composition root (commonly `EndPoints/...CommonConfigs/OtherApplicationServicesConfig.cs`).

```csharp
using Sumeru.Flex;
using Microsoft.Extensions.Options;

public static class OtherApplicationServicesConfig
{
	public static IServiceCollection AddOtherApplicationServices(
		this IServiceCollection services,
		IConfiguration configuration)
	{
		services.Configure<LocalFileStoreOptions>(
			configuration.GetSection("FlexBase:DataStores:File:LocalFileSystem"));

		services.AddSingleton<IFlexFileStore>(sp =>
		{
			var options = sp.GetRequiredService<IOptions<LocalFileStoreOptions>>().Value;
			return new LocalFileStore(options);
		});

		return services;
	}
}
```

## appsettings.json

You can choose any section name; this example uses `FlexBase:DataStores:File:LocalFileSystem`.

```json
{
  "FlexBase": {
	"DataStores": {
	  "File": {
		"LocalFileSystem": {
		  "BasePath": "D:/Data/{YourApplication}/files",
		  "CreateDirectoriesOnWrite": true
		}
	  }
	}
  }
}
```

## Examples (template-based)

These examples mirror the generated Query and PostBusHandler templates. You do **not** register these types manually—Flex discovers and wires generated Queries/Handlers automatically.

### Upload file (PostBusHandler)

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System.IO;
using System.Threading.Tasks;

namespace {YourApplication}.Handlers.Files;

public partial class UploadFileHandler : IAmFlexCommandHandler<UploadFileCommand>
{
	protected string EventCondition = "";
	protected readonly ILogger<UploadFileHandler> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexFileStore _fileStore;

	public UploadFileHandler(ILogger<UploadFileHandler> logger, IFlexHost flexHost, IFlexFileStore fileStore)
	{
		_logger = logger;
		_flexHost = flexHost;
		_fileStore = fileStore;
	}

	public virtual async Task Execute(UploadFileCommand cmd, IFlexServiceBusContext serviceBusContext)
	{
		var appContext = cmd.Dto.GetAppContext(); // do not remove this line
		var model = _flexHost.GetDomainModel<FileModel>().Create(cmd);

		var fileId = await _fileStore.UploadAsync(cmd.Dto.Stream, cmd.Dto.FileName, cmd.Dto.ContentType, cmd.Dto.Metadata);
		await this.Fire(EventCondition, serviceBusContext);
	}
}

public class UploadFileCommand : FlexCommandBridge<UploadFileDto> { }
public class UploadFileDto : DtoBridge
{
	public Stream Stream { get; set; }
	public string FileName { get; set; }
	public string ContentType { get; set; }
	public IDictionary<string, string>? Metadata { get; set; }
}
public class FileModel : FlexDomainModelBridge { }
```

### Download file (Query)

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System.IO;
using System.Threading.Tasks;

namespace {YourApplication}.Queries.Files;

public class DownloadFileQuery : FlexiQueryBridgeAsync<FileDownloadOutput>
{
	protected readonly IFlexFileStore _fileStore;
	protected DownloadFileParams _params;

	public DownloadFileQuery(ILogger<DownloadFileQuery> logger, IFlexHost flexHost, IFlexFileStore fileStore)
		=> _fileStore = fileStore;

	public virtual DownloadFileQuery AssignParameters(DownloadFileParams @params)
	{
		_params = @params;
		return this;
	}

	public virtual async Task<FileDownloadOutput?> Fetch()
	{
		var appContext = _params.GetAppContext();
		var stream = await _fileStore.DownloadAsync(_params.FileId);
		if (stream == null) return default;
		return new FileDownloadOutput { FileId = _params.FileId, Stream = stream };
	}
}

public class DownloadFileParams : DtoBridge { public string FileId { get; set; } }
public class FileDownloadOutput : DtoBridge { public string FileId { get; set; } public Stream Stream { get; set; } }
```

## Library-specific considerations

* **Path + permissions**: pick an absolute `BasePath` and ensure the app identity can read/write.
* **Multi-instance**: local disk is not shared across nodes; use a cloud provider if you need horizontal scale.
