Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
ef6ff45f40 | |||
3d5b7db864 | |||
9f29202764 | |||
47abd5b838 | |||
430e1d8617 | |||
ab8c4398f8 | |||
38444d5cd5 | |||
44ac877aae | |||
5417df81ea | |||
be6b8504be | |||
d3c4be572b |
28
.github/workflows/on-pr.yml
vendored
28
.github/workflows/on-pr.yml
vendored
@ -1,7 +1,7 @@
|
|||||||
name: build-packages
|
name: build-packages
|
||||||
on: pull_request
|
on: pull_request
|
||||||
jobs:
|
jobs:
|
||||||
connectors-packages:
|
build-check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
DOTNET_INSTALL_DIR: "/home/runner"
|
DOTNET_INSTALL_DIR: "/home/runner"
|
||||||
@ -24,3 +24,29 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- run: dotnet build --configuration Release
|
- run: dotnet build --configuration Release
|
||||||
|
run-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
DOTNET_INSTALL_DIR: "/home/runner"
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Cleanup build folder
|
||||||
|
run: |
|
||||||
|
rm -rf ./* ./.??* || true
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
dotnet-version: 8.0.x
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
run: |
|
||||||
|
dotnet test ./meilisearch.NET.Tests/meilisearch.NET.Tests.csproj
|
30
.github/workflows/on-push.yml
vendored
30
.github/workflows/on-push.yml
vendored
@ -6,7 +6,7 @@ on:
|
|||||||
- 'master'
|
- 'master'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
meilisearch-dotnet-packages:
|
nuget-package:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
DOTNET_INSTALL_DIR: "/home/runner"
|
DOTNET_INSTALL_DIR: "/home/runner"
|
||||||
@ -70,4 +70,30 @@ jobs:
|
|||||||
Automated release of MeiliSearch.NET version ${{ steps.gitversion.outputs.SemVer }}."
|
Automated release of MeiliSearch.NET version ${{ steps.gitversion.outputs.SemVer }}."
|
||||||
files: nuget-packages/*.nupkg
|
files: nuget-packages/*.nupkg
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: true
|
||||||
|
run-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
DOTNET_INSTALL_DIR: "/home/runner"
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Cleanup build folder
|
||||||
|
run: |
|
||||||
|
rm -rf ./* ./.??* || true
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
dotnet-version: 8.0.x
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
run: |
|
||||||
|
dotnet test ./meilisearch.NET.Tests/meilisearch.NET.Tests.csproj
|
34
.github/workflows/on-release.yml
vendored
Normal file
34
.github/workflows/on-release.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
name: update-release-status
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Get latest release
|
||||||
|
id: latest_release
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const release = await github.rest.repos.getLatestRelease({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo
|
||||||
|
});
|
||||||
|
return release.data;
|
||||||
|
|
||||||
|
- name: Update release
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const release = ${{ steps.latest_release.outputs.result }};
|
||||||
|
await github.rest.repos.updateRelease({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
release_id: release.id,
|
||||||
|
prerelease: false
|
||||||
|
});
|
268
README.md
268
README.md
@ -6,193 +6,181 @@
|
|||||||

|

|
||||||
[](#)
|
[](#)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
|
[](https://discord.gg/8dHnaarghJ)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
MeiliSearch .NET Integration is a NuGet package that seamlessly embeds MeiliSearch into your C# application. It manages the background process and health checks for you, simplifying the integration of full-text search capabilities. In future updates, it will also handle automatic compression and decompression of indexes to help manage local storage usage effectively.
|
MeiliSearch .NET Embedded is a powerful NuGet package that seamlessly integrates MeiliSearch into your .NET applications. It provides a robust wrapper around MeiliSearch, handling process management, health monitoring, and advanced features like index compression - all while maintaining compatibility with the native MeiliSearch SDK.
|
||||||
|
|
||||||
`You can use the default SDK for everything, but indexs that are disabled through the SDK wont appear until reenabled with the SDK.`
|
## Key Features
|
||||||
|
|
||||||
## Features
|
- **Embedded MeiliSearch Engine**: Run MeiliSearch directly within your application
|
||||||
|
- **Automatic Process Management**: Handles startup, shutdown, and health monitoring
|
||||||
- [x] **Embedded MeiliSearch**: Integrate MeiliSearch directly into your application.
|
- **Smart Index Management**:
|
||||||
- [x] **Manage Indexes**: Manage your indexs and documents through the SDK, you can still use the default Meilisearch SDK.
|
- Create and manage indexes with type safety
|
||||||
- [x] **Add Documents**: Ability to add documents and have validation on if the index is loaded.
|
- Enable/disable indexes on demand
|
||||||
- [x] **Document Batch System**: Automatic batch system for adding documents to indexes that will wait for configured threshold.
|
- Automatic compression for optimized storage
|
||||||
- [x] **Background Process Management**: Automatically handles the lifecycle of the MeiliSearch process.
|
- **Efficient Document Management**:
|
||||||
- [x] **Health Monitoring**: Regular checks on the health of the MeiliSearch instance to ensure it stays running.
|
- Batch processing system with configurable thresholds
|
||||||
- [x] **API Key Management**: An API key is automatically regenerated every time the MeiliSearch service starts unless one is specified in the configuration.
|
- Automatic validation of index availability
|
||||||
- [x] **Resource Monitoring**: Monitor the resources being used including storage by your MeiliSearch.
|
- **Resource Monitoring**:
|
||||||
- [x] **Future Index Management**: Upcoming feature to automatically compress and decompress indexes for optimized local storage.
|
- Track memory and CPU usage
|
||||||
- [x] **Caching Mechanism**: Cache the comrpessed indexes so they are returned when you ask for a list of all indexs.
|
- Monitor storage utilization
|
||||||
- [ ] **Search Capabilities**: Ability to use the meilisearch native search capabilities with the index being loaded validation.
|
- Index-specific metrics
|
||||||
- [ ] **Embedded Ollama**: Intergated Ollama directly into your application with a configured model.
|
- **Native SDK Compatibility**: Full support for the official MeiliSearch SDK
|
||||||
- [ ] **AI Search Capabilities**: Ability to use the meilisearch native AI search capabilities with the index being loaded validation.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To add the MeiliSearch .NET Integration package to your project, you can install it directly from NuGet. Follow the steps below based on your preferred method:
|
### Via Package Manager Console
|
||||||
|
|
||||||
### Package Manager Console
|
|
||||||
|
|
||||||
Open the Package Manager Console in Visual Studio and run the following command:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
Install-Package meilisearch.NET
|
Install-Package meilisearch.NET
|
||||||
```
|
```
|
||||||
|
|
||||||
### .NET CLI
|
### Via .NET CLI
|
||||||
|
|
||||||
If you're using the .NET CLI, run the following command in your terminal:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet add package meilisearch.NET
|
dotnet add package meilisearch.NET
|
||||||
```
|
```
|
||||||
|
|
||||||
## AppSettings Options
|
## Quick Start
|
||||||
|
|
||||||
- **Port**: The port on which MeiliSearch will run (default is `7700`).
|
### 1. Basic Setup
|
||||||
- **UiEnabled**: A boolean value to enable or disable the MeiliSearch UI (default is `true`).
|
Add MeiliSearch service to your dependency injection container:
|
||||||
- **ApiKey**: An optional API key. If specified, this key will be used; otherwise, a new key will be generated each time the service starts.
|
|
||||||
|
|
||||||
## Configuration
|
```csharp
|
||||||
|
var builder = Host.CreateApplicationBuilder();
|
||||||
|
builder.Services.AddMeiliSearchService();
|
||||||
|
```
|
||||||
|
|
||||||
The MeiliSearch service can be configured using the `MeiliSearchConfiguration` class. The following options are available:
|
### 2. Configuration
|
||||||
|
Configure MeiliSearch in your `appsettings.json`:
|
||||||
- **Port**: The port on which MeiliSearch will run (default is `7700`).
|
|
||||||
- **UiEnabled**: A boolean value to enable or disable the MeiliSearch UI (default is `true`).
|
|
||||||
- **ApiKey**: An optional API key. If specified, this key will be used; otherwise, a new key will be generated each time the service starts.
|
|
||||||
|
|
||||||
You can configure these options in your `appsettings.json` file as follows:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"MeiliSearch": {
|
"MeiliSearch": {
|
||||||
"Port": 7700,
|
"Port": 7700,
|
||||||
"UiEnabled": true,
|
"UiEnabled": true
|
||||||
"ApiKey": "your_api_key"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
### 3. Basic Usage
|
||||||
|
|
||||||
To set up the MeiliSearch service in your application, configure dependency injection as shown below:
|
|
||||||
|
|
||||||
|
#### Define Your Document Model
|
||||||
```csharp
|
```csharp
|
||||||
using System.Net;
|
public class Product : IDocument
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;
|
|
||||||
|
|
||||||
var builder = Host.CreateApplicationBuilder();
|
|
||||||
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
|
|
||||||
builder.Services.AddMeiliSearchService();
|
|
||||||
builder.Logging.ClearProviders();
|
|
||||||
builder.Logging.AddConsole();
|
|
||||||
builder.Logging.SetMinimumLevel(LogLevel.Information);
|
|
||||||
builder.Services.AddLogging();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
app.Run();
|
|
||||||
Console.ReadLine();
|
|
||||||
```
|
|
||||||
|
|
||||||
## MeiliSearchService Class Usage Guide
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
#### Start
|
|
||||||
|
|
||||||
Starts the MeiliSearch process. Logs the start of the process, sets the status to **Starting**, and attempts to start the process.
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
MeiliSearchService service = new MeiliSearchService();
|
|
||||||
service.Start();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Stop
|
|
||||||
|
|
||||||
Stops the MeiliSearch process. Logs the stop of the process, sets the status to **Stopping**, and attempts to stop the process.
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
service.Stop();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Restart
|
|
||||||
|
|
||||||
Restarts the MeiliSearch process. Stops the process using the **Stop** method and starts it using the **Start** method.
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
service.Restart();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### CreateIndex
|
|
||||||
|
|
||||||
Creates a new index with the specified name.
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
service.CreateIndex("my_index");
|
|
||||||
```
|
|
||||||
|
|
||||||
#### DeleteIndex
|
|
||||||
|
|
||||||
Deletes an existing index with the specified name.
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
service.DeleteIndex("my_index");
|
|
||||||
```
|
|
||||||
|
|
||||||
#### AddDocument
|
|
||||||
|
|
||||||
Adds a document to the specified index.
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class MyDocument : IDocument
|
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string Title { get; set; }
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public decimal Price { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
var document = new MyDocument { Id = "1", Title = "My Document" };
|
|
||||||
service.AddDocument("my_index", document);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### GetAllIndexes
|
#### Create and Manage Indexes
|
||||||
|
|
||||||
Retrieves a list of all existing indexes.
|
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
List<string> indexes = service.GetAllIndexes();
|
public class SearchService
|
||||||
|
{
|
||||||
|
private readonly MeiliSearchService _searchService;
|
||||||
|
|
||||||
|
public SearchService(MeiliSearchService searchService)
|
||||||
|
{
|
||||||
|
_searchService = searchService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitializeProductIndex()
|
||||||
|
{
|
||||||
|
// Create index
|
||||||
|
await _searchService.CreateIndex<Product>("products");
|
||||||
|
|
||||||
|
// Add documents
|
||||||
|
var product = new Product
|
||||||
|
{
|
||||||
|
Id = "1",
|
||||||
|
Name = "Gaming Laptop",
|
||||||
|
Description = "High-performance gaming laptop",
|
||||||
|
Price = 1299.99m
|
||||||
|
};
|
||||||
|
|
||||||
|
_searchService.AddDocument("products", product);
|
||||||
|
|
||||||
|
//_searchService.AddDocument("products", product, true); if you set the third parameter, which is autocommit, to true, it will ignore batching.
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
### 4. Use MeiliSearch SDK
|
||||||
### Status
|
### Using Native MeiliSearch SDK
|
||||||
|
|
||||||
Indicates the current status of the MeiliSearch process.
|
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
MeiliSearchStatus status = service.Status;
|
await _searchService.SDK("products", async client =>
|
||||||
|
{
|
||||||
|
var index = await client.GetIndex("products");
|
||||||
|
var searchResults = await index.SearchAsync<Product>("laptop");
|
||||||
|
return searchResults;
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notes
|
## Advanced Usage
|
||||||
https://github.com/Mozilla-Ocho/llamafile
|
|
||||||
|
|
||||||
|
### Resource Monitoring
|
||||||
|
```csharp
|
||||||
|
var usage = _searchService.GetResourceUsage();
|
||||||
|
Console.WriteLine($"Memory Usage: {usage.MemoryUsageBytes} bytes");
|
||||||
|
Console.WriteLine($"CPU Usage: {usage.CpuPercentage}%");
|
||||||
|
Console.WriteLine($"Storage Usage: {_searchService.GetTotalStorageUsage()} bytes");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Index Management
|
||||||
|
```csharp
|
||||||
|
// Disable an index (automatically compresses)
|
||||||
|
await _searchService.SetIndexEnabled("products", false);
|
||||||
|
|
||||||
|
// Enable an index (automatically decompresses)
|
||||||
|
await _searchService.SetIndexEnabled("products", true);
|
||||||
|
|
||||||
|
// Get all indexes
|
||||||
|
var indexes = await _searchService.GetAllIndexes();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Resource Management**
|
||||||
|
- Always dispose of the `MeiliSearchService` when your application shuts down
|
||||||
|
- Monitor resource usage in production environments
|
||||||
|
|
||||||
|
2. **Index Management**
|
||||||
|
- Disable unused indexes to save resources
|
||||||
|
- Use type-safe index creation with generic parameters
|
||||||
|
|
||||||
|
3. **Document Management**
|
||||||
|
- Utilize batch processing for bulk operations
|
||||||
|
- Handle exceptions when adding documents
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
- The batch system automatically manages document additions with a default threshold of 100 documents
|
||||||
|
- Compressed indexes use less storage but require decompression before use
|
||||||
|
- Monitor resource usage in production environments
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We welcome contributions! Please follow these steps:
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create a feature branch
|
||||||
|
3. Commit your changes
|
||||||
|
4. Push to the branch
|
||||||
|
5. Create a Pull Request
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
We welcome contributions! Please feel free to submit issues, pull requests, or suggestions to improve this project.
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
For any issues or questions, please open an issue on GitHub or contact us via [your contact method].
|
- Create an issue on GitHub
|
||||||
|
- Contact us on discord [](https://discord.gg/8dHnaarghJ)
|
||||||
|
- Visit our documentation at meilisearchdotnet.d4m13n.dev
|
||||||
|
|
||||||
---
|
## Acknowledgments
|
||||||
|
|
||||||
Feel free to customize this README as necessary for your package, especially regarding the project name and license details!
|
- Built on top of the excellent [MeiliSearch](https://www.meilisearch.com/) search engine
|
||||||
|
- Powered by [Ollama](https://ollama.ai/) for AI capabilities
|
||||||
---
|
|
||||||
|
211
meilisearch.NET.Tests/MeilisearchServiceTests.cs
Normal file
211
meilisearch.NET.Tests/MeilisearchServiceTests.cs
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Meilisearch;
|
||||||
|
using meilisearch.NET.Interfaces;
|
||||||
|
using meilisearch.NET.Models;
|
||||||
|
using meilisearch.NET.Services.DocumentManagement;
|
||||||
|
using meilisearch.NET.Services.IndexManagement;
|
||||||
|
using meilisearch.NET.Services.ProcessManagement;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace meilisearch.NET.Tests
|
||||||
|
{
|
||||||
|
public class MeiliSearchServiceTests
|
||||||
|
{
|
||||||
|
private readonly Mock<IProcessManager> _mockProcessManager;
|
||||||
|
private readonly Mock<IIndexManager> _mockIndexManager;
|
||||||
|
private readonly Mock<IDocumentManager> _mockDocumentManager;
|
||||||
|
private readonly Mock<MeilisearchClient> _mockClient;
|
||||||
|
private readonly MeiliSearchService _service;
|
||||||
|
|
||||||
|
public MeiliSearchServiceTests()
|
||||||
|
{
|
||||||
|
_mockProcessManager = new Mock<IProcessManager>();
|
||||||
|
_mockIndexManager = new Mock<IIndexManager>();
|
||||||
|
_mockDocumentManager = new Mock<IDocumentManager>();
|
||||||
|
|
||||||
|
_service = new MeiliSearchService(
|
||||||
|
_mockProcessManager.Object,
|
||||||
|
_mockIndexManager.Object,
|
||||||
|
_mockDocumentManager.Object
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Start_CallsProcessManagerStartProcess()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_mockProcessManager.Setup(x => x.StartProcess()).Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await _service.Start();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockProcessManager.Verify(x => x.StartProcess(), Times.Exactly(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetTotalStorageUsage_CallsIndexManagerWithCorrectParameters()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const bool useCompressedSize = true;
|
||||||
|
const long expectedUsage = 1000L;
|
||||||
|
_mockIndexManager.Setup(x => x.GetTotalStorageUsage(useCompressedSize)).Returns(expectedUsage);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = _service.GetTotalStorageUsage(useCompressedSize);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedUsage, result);
|
||||||
|
_mockIndexManager.Verify(x => x.GetTotalStorageUsage(useCompressedSize), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetIndexStorageUsage_CallsIndexManagerWithCorrectParameters()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string indexName = "testIndex";
|
||||||
|
const bool useCompressedSize = true;
|
||||||
|
const long expectedUsage = 500L;
|
||||||
|
_mockIndexManager.Setup(x => x.GetIndexStorageUsage(indexName, useCompressedSize)).Returns(expectedUsage);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = _service.GetIndexStorageUsage(indexName, useCompressedSize);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedUsage, result);
|
||||||
|
_mockIndexManager.Verify(x => x.GetIndexStorageUsage(indexName, useCompressedSize), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Stop_CallsProcessManagerStopProcess()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
_service.Stop();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockProcessManager.Verify(x => x.StopProcess(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsRunning_ReturnsProcessManagerStatus()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const bool expectedStatus = true;
|
||||||
|
_mockProcessManager.Setup(x => x.IsProcessRunning()).Returns(expectedStatus);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = _service.IsRunning();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedStatus, result);
|
||||||
|
_mockProcessManager.Verify(x => x.IsProcessRunning(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SetIndexEnabled_CallsIndexManagerWithCorrectParameters()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string indexName = "testIndex";
|
||||||
|
const bool enabled = true;
|
||||||
|
_mockIndexManager.Setup(x => x.SetIndexEnabledAsync(indexName, enabled)).Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await _service.SetIndexEnabled(indexName, enabled);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockIndexManager.Verify(x => x.SetIndexEnabledAsync(indexName, enabled), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetResourceUsage_ReturnsProcessManagerStats()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedStats = new ProcessResourceStats();
|
||||||
|
_mockProcessManager.Setup(x => x.GetResourceUsage()).Returns(expectedStats);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = _service.GetResourceUsage();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(expectedStats, result);
|
||||||
|
_mockProcessManager.Verify(x => x.GetResourceUsage(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetAllIndexes_ReturnsIndexManagerResults()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedIndexes = new List<string> { "index1", "index2" };
|
||||||
|
_mockIndexManager.Setup(x => x.GetAllIndexes()).ReturnsAsync(expectedIndexes);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _service.GetAllIndexes();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedIndexes, result);
|
||||||
|
_mockIndexManager.Verify(x => x.GetAllIndexes(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateIndex_CallsIndexManagerWithCorrectParameters()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string indexName = "testIndex";
|
||||||
|
_mockIndexManager.Setup(x => x.CreateIndexAsync<TestDocument>(indexName)).Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await _service.CreateIndex<TestDocument>(indexName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockIndexManager.Verify(x => x.CreateIndexAsync<TestDocument>(indexName), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeleteIndex_CallsIndexManagerWithCorrectParameters()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string indexName = "testIndex";
|
||||||
|
_mockIndexManager.Setup(x => x.DeleteIndexAsync(indexName)).Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await _service.DeleteIndex(indexName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockIndexManager.Verify(x => x.DeleteIndexAsync(indexName), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddDocument_CallsDocumentManagerWithCorrectParameters()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string repositoryId = "testRepo";
|
||||||
|
var document = new TestDocument();
|
||||||
|
const bool autoCommit = true;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
_service.AddDocument(repositoryId, document, autoCommit);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockDocumentManager.Verify(x => x.AddDocument(repositoryId, document, autoCommit), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Dispose_CallsProcessManagerDispose()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
_service.Dispose();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockProcessManager.Verify(x => x.Dispose(), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class for testing
|
||||||
|
private class TestDocument : IDocument
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
meilisearch.NET.Tests/meilisearch.NET.Tests.csproj
Normal file
28
meilisearch.NET.Tests/meilisearch.NET.Tests.csproj
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
<RootNamespace>TestProject1</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
||||||
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
|
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\meilisearch.NET\meilisearch.NET.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||||||
using meilisearch.NET;
|
using meilisearch.NET;
|
||||||
using meilisearch.NET.Configurations;
|
using meilisearch.NET.Configurations;
|
||||||
using meilisearch.NET.example;
|
using meilisearch.NET.example;
|
||||||
|
using meilisearch.NET.Extensions;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "meilisearch.NET", "meilisea
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "meilisearch.NET.example", "meilisearch.NET.example\meilisearch.NET.example.csproj", "{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "meilisearch.NET.example", "meilisearch.NET.example\meilisearch.NET.example.csproj", "{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "meilisearch.NET.Tests", "meilisearch.NET.Tests\meilisearch.NET.Tests.csproj", "{FDCF4472-79F8-4AF2-AB02-00522C399E22}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -18,5 +20,9 @@ Global
|
|||||||
{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E753BBD6-6ADF-4DD4-8822-7279CD55DF58}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FDCF4472-79F8-4AF2-AB02-00522C399E22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FDCF4472-79F8-4AF2-AB02-00522C399E22}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FDCF4472-79F8-4AF2-AB02-00522C399E22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FDCF4472-79F8-4AF2-AB02-00522C399E22}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
namespace meilisearch.NET.Enums;
|
|
||||||
|
|
||||||
public enum MeiliSearchStatus
|
|
||||||
{
|
|
||||||
Stopped,
|
|
||||||
Starting,
|
|
||||||
Running,
|
|
||||||
Stopping,
|
|
||||||
Crashed
|
|
||||||
}
|
|
12
meilisearch.NET/Exceptions/IndexAlreadyExistsException.cs
Normal file
12
meilisearch.NET/Exceptions/IndexAlreadyExistsException.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
public class IndexAlreadyExistsException : IndexManagementException
|
||||||
|
{
|
||||||
|
public string IndexName { get; }
|
||||||
|
|
||||||
|
public IndexAlreadyExistsException(string indexName)
|
||||||
|
: base($"Index '{indexName}' already exists")
|
||||||
|
{
|
||||||
|
IndexName = indexName;
|
||||||
|
}
|
||||||
|
}
|
12
meilisearch.NET/Exceptions/IndexCompressionException.cs
Normal file
12
meilisearch.NET/Exceptions/IndexCompressionException.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
public class IndexCompressionException : IndexManagementException
|
||||||
|
{
|
||||||
|
public string IndexName { get; }
|
||||||
|
|
||||||
|
public IndexCompressionException(string indexName, string operation, Exception innerException)
|
||||||
|
: base($"Failed to {operation} index '{indexName}'", innerException)
|
||||||
|
{
|
||||||
|
IndexName = indexName;
|
||||||
|
}
|
||||||
|
}
|
7
meilisearch.NET/Exceptions/IndexLimitReachedException.cs
Normal file
7
meilisearch.NET/Exceptions/IndexLimitReachedException.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
public class IndexLimitReachedException : IndexManagementException
|
||||||
|
{
|
||||||
|
public IndexLimitReachedException()
|
||||||
|
: base("Maximum number of indexes (1000) has been reached") { }
|
||||||
|
}
|
10
meilisearch.NET/Exceptions/IndexManagementException.cs
Normal file
10
meilisearch.NET/Exceptions/IndexManagementException.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown when there are issues with index management
|
||||||
|
/// </summary>
|
||||||
|
public class IndexManagementException : MeiliSearchException
|
||||||
|
{
|
||||||
|
public IndexManagementException(string message) : base(message) { }
|
||||||
|
public IndexManagementException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
12
meilisearch.NET/Exceptions/IndexNotFoundException.cs
Normal file
12
meilisearch.NET/Exceptions/IndexNotFoundException.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
public class IndexNotFoundException : IndexManagementException
|
||||||
|
{
|
||||||
|
public string IndexName { get; }
|
||||||
|
|
||||||
|
public IndexNotFoundException(string indexName)
|
||||||
|
: base($"Index '{indexName}' not found")
|
||||||
|
{
|
||||||
|
IndexName = indexName;
|
||||||
|
}
|
||||||
|
}
|
10
meilisearch.NET/Exceptions/MeiliSearchException.cs
Normal file
10
meilisearch.NET/Exceptions/MeiliSearchException.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base exception class for all Meilisearch.NET exceptions
|
||||||
|
/// </summary>
|
||||||
|
public class MeiliSearchException : Exception
|
||||||
|
{
|
||||||
|
public MeiliSearchException(string message) : base(message) { }
|
||||||
|
public MeiliSearchException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
10
meilisearch.NET/Exceptions/ProcessManagementException.cs
Normal file
10
meilisearch.NET/Exceptions/ProcessManagementException.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception thrown when there are issues with the Meilisearch process management
|
||||||
|
/// </summary>
|
||||||
|
public class ProcessManagementException : MeiliSearchException
|
||||||
|
{
|
||||||
|
public ProcessManagementException(string message) : base(message) { }
|
||||||
|
public ProcessManagementException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
6
meilisearch.NET/Exceptions/ProcessNotRunningException.cs
Normal file
6
meilisearch.NET/Exceptions/ProcessNotRunningException.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
public class ProcessNotRunningException : ProcessManagementException
|
||||||
|
{
|
||||||
|
public ProcessNotRunningException() : base("Meilisearch process is not running") { }
|
||||||
|
}
|
6
meilisearch.NET/Exceptions/ProcessStartException.cs
Normal file
6
meilisearch.NET/Exceptions/ProcessStartException.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
public class ProcessStartException : ProcessManagementException
|
||||||
|
{
|
||||||
|
public ProcessStartException(Exception innerException, string message) : base($"Failed to start Meilisearch process: {message}", innerException) { }
|
||||||
|
}
|
6
meilisearch.NET/Exceptions/ProcessStopException.cs
Normal file
6
meilisearch.NET/Exceptions/ProcessStopException.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace meilisearch.NET.Exceptions;
|
||||||
|
|
||||||
|
public class ProcessStopException : ProcessManagementException
|
||||||
|
{
|
||||||
|
public ProcessStopException(Exception innerException, string message) : base($"Failed to stop Meilisearch process: {message}", innerException) { }
|
||||||
|
}
|
@ -1,9 +1,21 @@
|
|||||||
using Meilisearch;
|
using Meilisearch;
|
||||||
using meilisearch.NET;
|
|
||||||
using meilisearch.NET.Models;
|
|
||||||
|
|
||||||
|
namespace meilisearch.NET.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for executing operations on MeiliSearch client.
|
||||||
|
/// </summary>
|
||||||
public static class MeilisearchClientExtensions
|
public static class MeilisearchClientExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Executes an action against MeiliSearch client that returns a value, automatically handling compressed index states.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of value returned by the action</typeparam>
|
||||||
|
/// <param name="service">The MeiliSearch service instance</param>
|
||||||
|
/// <param name="indexName">Name of the index to operate on</param>
|
||||||
|
/// <param name="action">The action to execute against the MeiliSearch client</param>
|
||||||
|
/// <returns>The result of the executed action</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown when MeiliSearch client is not initialized</exception>
|
||||||
public static async Task<T> SDK<T>(this MeiliSearchService service, string indexName, Func<MeilisearchClient, Task<T>> action)
|
public static async Task<T> SDK<T>(this MeiliSearchService service, string indexName, Func<MeilisearchClient, Task<T>> action)
|
||||||
{
|
{
|
||||||
var client = service.Client;
|
var client = service.Client;
|
||||||
@ -26,6 +38,13 @@ public static class MeilisearchClientExtensions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes an action against MeiliSearch client that doesn't return a value, automatically handling compressed index states.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="service">The MeiliSearch service instance</param>
|
||||||
|
/// <param name="indexName">Name of the index to operate on</param>
|
||||||
|
/// <param name="action">The action to execute against the MeiliSearch client</param>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown when MeiliSearch client is not initialized</exception>
|
||||||
public static async Task SDK(this MeiliSearchService service, string indexName, Func<MeilisearchClient, Task> action)
|
public static async Task SDK(this MeiliSearchService service, string indexName, Func<MeilisearchClient, Task> action)
|
||||||
{
|
{
|
||||||
var client = service.Client;
|
var client = service.Client;
|
||||||
|
@ -1,13 +1,31 @@
|
|||||||
using Meilisearch;
|
using Meilisearch;
|
||||||
using meilisearch.NET;
|
|
||||||
using meilisearch.NET.Configurations;
|
using meilisearch.NET.Configurations;
|
||||||
using meilisearch.NET.Services.DocumentManagement;
|
using meilisearch.NET.Services.DocumentManagement;
|
||||||
using meilisearch.NET.Services.IndexManagement;
|
using meilisearch.NET.Services.IndexManagement;
|
||||||
using meilisearch.NET.Services.ProcessManagement;
|
using meilisearch.NET.Services.ProcessManagement;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace meilisearch.NET.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for IServiceCollection to configure MeiliSearch services
|
||||||
|
/// </summary>
|
||||||
public static class ServiceCollectionExtension
|
public static class ServiceCollectionExtension
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds MeiliSearch services to the dependency injection container
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The IServiceCollection to add services to</param>
|
||||||
|
/// <returns>The IServiceCollection for chaining</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// Registers the following services as singletons:
|
||||||
|
/// - MeilisearchClient (configured for localhost:7700)
|
||||||
|
/// - MeiliSearchService (with HttpClient)
|
||||||
|
/// - MeiliSearchConfiguration
|
||||||
|
/// - MeiliSearchProcessManager
|
||||||
|
/// - IIndexManager (implemented by IndexManager)
|
||||||
|
/// - IDocumentManager (implemented by DocumentManager)
|
||||||
|
/// </remarks>
|
||||||
public static IServiceCollection AddMeiliSearchService(this IServiceCollection services)
|
public static IServiceCollection AddMeiliSearchService(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<MeilisearchClient>(sp =>
|
services.AddSingleton<MeilisearchClient>(sp =>
|
||||||
@ -16,7 +34,7 @@ public static class ServiceCollectionExtension
|
|||||||
});
|
});
|
||||||
services.AddHttpClient<MeiliSearchService>();
|
services.AddHttpClient<MeiliSearchService>();
|
||||||
services.AddSingleton<MeiliSearchConfiguration>();
|
services.AddSingleton<MeiliSearchConfiguration>();
|
||||||
services.AddSingleton< MeiliSearchProcessManager>();
|
services.AddSingleton<MeiliSearchProcessManager>();
|
||||||
services.AddSingleton<IIndexManager, IndexManager>();
|
services.AddSingleton<IIndexManager, IndexManager>();
|
||||||
services.AddSingleton<IDocumentManager, DocumentManager>();
|
services.AddSingleton<IDocumentManager, DocumentManager>();
|
||||||
services.AddSingleton<MeiliSearchService>();
|
services.AddSingleton<MeiliSearchService>();
|
||||||
|
@ -1,55 +1,96 @@
|
|||||||
using Meilisearch;
|
using Meilisearch;
|
||||||
using meilisearch.NET.Interfaces;
|
using meilisearch.NET.Interfaces;
|
||||||
|
using meilisearch.NET.Models;
|
||||||
using meilisearch.NET.Services.DocumentManagement;
|
using meilisearch.NET.Services.DocumentManagement;
|
||||||
using meilisearch.NET.Services.IndexManagement;
|
using meilisearch.NET.Services.IndexManagement;
|
||||||
using meilisearch.NET.Services.ProcessManagement;
|
using meilisearch.NET.Services.ProcessManagement;
|
||||||
|
|
||||||
namespace meilisearch.NET;
|
namespace meilisearch.NET;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main service class for interacting with Meilisearch. Manages process, indexes and documents.
|
||||||
|
/// </summary>
|
||||||
public class MeiliSearchService : IDisposable
|
public class MeiliSearchService : IDisposable
|
||||||
{
|
{
|
||||||
internal readonly MeiliSearchProcessManager ProcessManager;
|
internal readonly IProcessManager ProcessManager;
|
||||||
internal readonly IIndexManager IndexManager;
|
internal readonly IIndexManager IndexManager;
|
||||||
internal readonly IDocumentManager DocumentManager;
|
internal readonly IDocumentManager DocumentManager;
|
||||||
internal readonly MeilisearchClient Client;
|
internal readonly MeilisearchClient Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of MeiliSearchService
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="processManager">Manager for the Meilisearch process</param>
|
||||||
|
/// <param name="indexManager">Manager for index operations</param>
|
||||||
|
/// <param name="documentManager">Manager for document operations</param>
|
||||||
public MeiliSearchService(
|
public MeiliSearchService(
|
||||||
MeiliSearchProcessManager processManager,
|
IProcessManager processManager,
|
||||||
IIndexManager indexManager,
|
IIndexManager indexManager,
|
||||||
IDocumentManager documentManager,
|
IDocumentManager documentManager)
|
||||||
MeilisearchClient client)
|
|
||||||
{
|
{
|
||||||
Client = client;
|
|
||||||
ProcessManager = processManager;
|
ProcessManager = processManager;
|
||||||
IndexManager = indexManager;
|
IndexManager = indexManager;
|
||||||
DocumentManager = documentManager;
|
DocumentManager = documentManager;
|
||||||
ProcessManager.StartProcess().Wait();
|
ProcessManager.StartProcess().Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Starts the Meilisearch process</summary>
|
||||||
public async Task Start() => await ProcessManager.StartProcess();
|
public async Task Start() => await ProcessManager.StartProcess();
|
||||||
|
|
||||||
|
/// <summary>Gets the total storage usage across all indexes</summary>
|
||||||
|
/// <param name="useCompressedSize">If true, returns compressed size for compressed indexes</param>
|
||||||
|
/// <returns>Total storage usage in bytes</returns>
|
||||||
public long GetTotalStorageUsage(bool useCompressedSize = true)
|
public long GetTotalStorageUsage(bool useCompressedSize = true)
|
||||||
=> IndexManager.GetTotalStorageUsage(useCompressedSize);
|
=> IndexManager.GetTotalStorageUsage(useCompressedSize);
|
||||||
|
|
||||||
|
/// <summary>Gets the storage usage for a specific index</summary>
|
||||||
|
/// <param name="indexName">Name of the index</param>
|
||||||
|
/// <param name="useCompressedSize">If true, returns compressed size for compressed indexes</param>
|
||||||
|
/// <returns>Index storage usage in bytes</returns>
|
||||||
public long GetIndexStorageUsage(string indexName, bool useCompressedSize = true)
|
public long GetIndexStorageUsage(string indexName, bool useCompressedSize = true)
|
||||||
=> IndexManager.GetIndexStorageUsage(indexName, useCompressedSize);
|
=> IndexManager.GetIndexStorageUsage(indexName, useCompressedSize);
|
||||||
|
|
||||||
|
/// <summary>Stops the Meilisearch process</summary>
|
||||||
public void Stop() => ProcessManager.StopProcess();
|
public void Stop() => ProcessManager.StopProcess();
|
||||||
|
|
||||||
|
/// <summary>Checks if the Meilisearch process is running</summary>
|
||||||
|
/// <returns>True if process is running, false otherwise</returns>
|
||||||
public bool IsRunning() => ProcessManager.IsProcessRunning();
|
public bool IsRunning() => ProcessManager.IsProcessRunning();
|
||||||
|
|
||||||
|
/// <summary>Enables or disables an index</summary>
|
||||||
|
/// <param name="indexName">Name of the index</param>
|
||||||
|
/// <param name="enabled">True to enable, false to disable</param>
|
||||||
public Task SetIndexEnabled(string indexName, bool enabled)
|
public Task SetIndexEnabled(string indexName, bool enabled)
|
||||||
=> IndexManager.SetIndexEnabledAsync(indexName, enabled);
|
=> IndexManager.SetIndexEnabledAsync(indexName, enabled);
|
||||||
|
|
||||||
|
/// <summary>Gets current resource usage statistics for the Meilisearch process</summary>
|
||||||
|
/// <returns>Process resource statistics</returns>
|
||||||
public ProcessResourceStats GetResourceUsage() => ProcessManager.GetResourceUsage();
|
public ProcessResourceStats GetResourceUsage() => ProcessManager.GetResourceUsage();
|
||||||
|
|
||||||
|
/// <summary>Gets a list of all index names</summary>
|
||||||
|
/// <returns>List of index names</returns>
|
||||||
public Task<List<string>> GetAllIndexes() => IndexManager.GetAllIndexes();
|
public Task<List<string>> GetAllIndexes() => IndexManager.GetAllIndexes();
|
||||||
|
|
||||||
|
/// <summary>Creates a new index</summary>
|
||||||
|
/// <typeparam name="T">Document type that implements IDocument</typeparam>
|
||||||
|
/// <param name="indexName">Name for the new index</param>
|
||||||
public Task CreateIndex<T>(string indexName) where T : IDocument
|
public Task CreateIndex<T>(string indexName) where T : IDocument
|
||||||
=> IndexManager.CreateIndexAsync<T>(indexName);
|
=> IndexManager.CreateIndexAsync<T>(indexName);
|
||||||
|
|
||||||
|
/// <summary>Deletes an existing index</summary>
|
||||||
|
/// <param name="indexName">Name of the index to delete</param>
|
||||||
public Task DeleteIndex(string indexName) => IndexManager.DeleteIndexAsync(indexName);
|
public Task DeleteIndex(string indexName) => IndexManager.DeleteIndexAsync(indexName);
|
||||||
|
|
||||||
|
/// <summary>Adds a document to an index</summary>
|
||||||
|
/// <param name="repositoryId">ID of the target repository/index</param>
|
||||||
|
/// <param name="document">Document to add</param>
|
||||||
|
/// <param name="autoCommit">If true, immediately syncs to server</param>
|
||||||
public void AddDocument(string repositoryId, IDocument document, bool autoCommit = false)
|
public void AddDocument(string repositoryId, IDocument document, bool autoCommit = false)
|
||||||
=> DocumentManager.AddDocument(repositoryId, document, autoCommit);
|
=> DocumentManager.AddDocument(repositoryId, document, autoCommit);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes the MeiliSearchService instance and its associated process manager
|
||||||
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
ProcessManager.Dispose();
|
ProcessManager.Dispose();
|
||||||
|
@ -1,16 +1,51 @@
|
|||||||
namespace meilisearch.NET.Models;
|
namespace meilisearch.NET.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Meilisearch index with its metadata and compression state.
|
||||||
|
/// </summary>
|
||||||
public class Index
|
public class Index
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of the index.
|
||||||
|
/// </summary>
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the creation timestamp of the index in UTC.
|
||||||
|
/// </summary>
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the unique folder identifier where the index data is stored.
|
||||||
|
/// </summary>
|
||||||
public string FolderId { get; set; } = string.Empty;
|
public string FolderId { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the index is currently compressed.
|
||||||
|
/// </summary>
|
||||||
public bool IsCompressed { get; set; } = false;
|
public bool IsCompressed { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the timestamp when the index was last compressed.
|
||||||
|
/// </summary>
|
||||||
public DateTime? LastCompressedAt { get; set; }
|
public DateTime? LastCompressedAt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the size of the index in bytes before compression.
|
||||||
|
/// </summary>
|
||||||
public long? SizeBeforeCompression { get; set; } = 0;
|
public long? SizeBeforeCompression { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the Index class.
|
||||||
|
/// </summary>
|
||||||
public Index() { }
|
public Index() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the Index class with specified parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the index.</param>
|
||||||
|
/// <param name="folderId">The folder identifier where index data is stored.</param>
|
||||||
|
/// <param name="createdAt">The creation timestamp of the index.</param>
|
||||||
public Index(string name, string folderId, DateTime createdAt)
|
public Index(string name, string folderId, DateTime createdAt)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
@ -1,11 +1,37 @@
|
|||||||
namespace meilisearch.NET.Models;
|
namespace meilisearch.NET.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents resource usage statistics for a Meilisearch process
|
||||||
|
/// </summary>
|
||||||
public class MeilisearchUsageStats
|
public class MeilisearchUsageStats
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CPU usage as a percentage (0-100)
|
||||||
|
/// </summary>
|
||||||
public double CpuPercentage { get; set; }
|
public double CpuPercentage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Memory usage in bytes
|
||||||
|
/// </summary>
|
||||||
public long MemoryUsageBytes { get; set; }
|
public long MemoryUsageBytes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total bytes read from disk
|
||||||
|
/// </summary>
|
||||||
public long DiskReadBytes { get; set; }
|
public long DiskReadBytes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total bytes written to disk
|
||||||
|
/// </summary>
|
||||||
public long DiskWriteBytes { get; set; }
|
public long DiskWriteBytes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of threads used by the process
|
||||||
|
/// </summary>
|
||||||
public int ThreadCount { get; set; }
|
public int ThreadCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process identifier
|
||||||
|
/// </summary>
|
||||||
public int ProcessId { get; set; }
|
public int ProcessId { get; set; }
|
||||||
}
|
}
|
37
meilisearch.NET/Models/ProcessResourceStats.cs
Normal file
37
meilisearch.NET/Models/ProcessResourceStats.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
namespace meilisearch.NET.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents resource usage statistics for a process at a point in time.
|
||||||
|
/// </summary>
|
||||||
|
public record ProcessResourceStats
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CPU usage percentage of the process.
|
||||||
|
/// </summary>
|
||||||
|
public double CpuPercentage { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the memory usage in bytes of the process.
|
||||||
|
/// </summary>
|
||||||
|
public long MemoryUsageBytes { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the total number of bytes read from disk by the process.
|
||||||
|
/// </summary>
|
||||||
|
public long DiskReadBytes { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the total number of bytes written to disk by the process.
|
||||||
|
/// </summary>
|
||||||
|
public long DiskWriteBytes { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the process identifier.
|
||||||
|
/// </summary>
|
||||||
|
public int ProcessId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of threads currently running in the process.
|
||||||
|
/// </summary>
|
||||||
|
public int ThreadCount { get; init; }
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using Meilisearch;
|
using Meilisearch;
|
||||||
|
using meilisearch.NET.Exceptions;
|
||||||
using meilisearch.NET.Interfaces;
|
using meilisearch.NET.Interfaces;
|
||||||
|
using meilisearch.NET.Services.ProcessManagement;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace meilisearch.NET.Services.DocumentManagement;
|
namespace meilisearch.NET.Services.DocumentManagement;
|
||||||
@ -9,13 +11,15 @@ namespace meilisearch.NET.Services.DocumentManagement;
|
|||||||
public class DocumentManager:IDocumentManager
|
public class DocumentManager:IDocumentManager
|
||||||
{
|
{
|
||||||
private readonly ILogger<DocumentManager> _logger;
|
private readonly ILogger<DocumentManager> _logger;
|
||||||
|
private readonly MeiliSearchProcessManager _meiliSearchProcessManager;
|
||||||
private readonly MeilisearchClient _client;
|
private readonly MeilisearchClient _client;
|
||||||
|
|
||||||
private const int THRESHOLD = 100;
|
private const int THRESHOLD = 100;
|
||||||
private ObservableCollection<KeyValuePair<string,IDocument>> _documentCollection;
|
private ObservableCollection<KeyValuePair<string,IDocument>> _documentCollection;
|
||||||
|
|
||||||
public DocumentManager(MeilisearchClient client, ILogger<DocumentManager> logger)
|
public DocumentManager(MeilisearchClient client, ILogger<DocumentManager> logger, MeiliSearchProcessManager meiliSearchProcessManager)
|
||||||
{
|
{
|
||||||
|
_meiliSearchProcessManager = meiliSearchProcessManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_client = client;
|
_client = client;
|
||||||
_documentCollection = new ObservableCollection<KeyValuePair<string,IDocument>>();
|
_documentCollection = new ObservableCollection<KeyValuePair<string,IDocument>>();
|
||||||
@ -24,16 +28,22 @@ public class DocumentManager:IDocumentManager
|
|||||||
|
|
||||||
public async Task AddDocumentAsync(string repositoryId, IDocument document, bool autoCommit = false)
|
public async Task AddDocumentAsync(string repositoryId, IDocument document, bool autoCommit = false)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
_logger.LogTrace($"Adding document '{document.Id}' to repository '{repositoryId}'...");
|
_logger.LogTrace($"Adding document '{document.Id}' to repository '{repositoryId}'...");
|
||||||
_documentCollection.Add(new KeyValuePair<string, IDocument>(repositoryId, document));
|
_documentCollection.Add(new KeyValuePair<string, IDocument>(repositoryId, document));
|
||||||
_logger.LogInformation($"Document {document.Id} added to collection.");
|
_logger.LogInformation($"Document {document.Id} added to collection.");
|
||||||
if (autoCommit)
|
if (autoCommit)
|
||||||
{
|
{
|
||||||
SyncDocumentsToServer();
|
await SyncDocumentsToServerAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void AddDocument(string repositoryId, IDocument document, bool autoCommit = false)
|
public void AddDocument(string repositoryId, IDocument document, bool autoCommit = false)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
_logger.LogTrace($"Adding document '{document.Id}' to repository '{repositoryId}'...");
|
_logger.LogTrace($"Adding document '{document.Id}' to repository '{repositoryId}'...");
|
||||||
_documentCollection.Add(new KeyValuePair<string, IDocument>(repositoryId, document));
|
_documentCollection.Add(new KeyValuePair<string, IDocument>(repositoryId, document));
|
||||||
_logger.LogInformation($"Document {document.Id} added to collection.");
|
_logger.LogInformation($"Document {document.Id} added to collection.");
|
||||||
@ -44,6 +54,9 @@ public class DocumentManager:IDocumentManager
|
|||||||
}
|
}
|
||||||
public void SyncDocumentsToServer()
|
public void SyncDocumentsToServer()
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var grouped = _documentCollection.GroupBy(pair => pair.Key)
|
var grouped = _documentCollection.GroupBy(pair => pair.Key)
|
||||||
.ToDictionary(group => group.Key, group => group.Select(pair => pair.Value).ToList());
|
.ToDictionary(group => group.Key, group => group.Select(pair => pair.Value).ToList());
|
||||||
foreach (var repository in grouped)
|
foreach (var repository in grouped)
|
||||||
@ -56,6 +69,9 @@ public class DocumentManager:IDocumentManager
|
|||||||
}
|
}
|
||||||
public async Task SyncDocumentsToServerAsync()
|
public async Task SyncDocumentsToServerAsync()
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var grouped = _documentCollection.GroupBy(pair => pair.Key)
|
var grouped = _documentCollection.GroupBy(pair => pair.Key)
|
||||||
.ToDictionary(group => group.Key, group => group.Select(pair => pair.Value).ToList());
|
.ToDictionary(group => group.Key, group => group.Select(pair => pair.Value).ToList());
|
||||||
foreach (var repository in grouped)
|
foreach (var repository in grouped)
|
||||||
|
@ -2,10 +2,34 @@ using meilisearch.NET.Interfaces;
|
|||||||
|
|
||||||
namespace meilisearch.NET.Services.DocumentManagement;
|
namespace meilisearch.NET.Services.DocumentManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages document operations for Meilisearch indexes.
|
||||||
|
/// </summary>
|
||||||
public interface IDocumentManager
|
public interface IDocumentManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a document to the specified repository.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repositoryId">The ID of the repository to add the document to.</param>
|
||||||
|
/// <param name="document">The document to add.</param>
|
||||||
|
/// <param name="autoCommit">If true, automatically syncs the document to the server.</param>
|
||||||
void AddDocument(string repositoryId, IDocument document, bool autoCommit = false);
|
void AddDocument(string repositoryId, IDocument document, bool autoCommit = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronizes all pending documents to the Meilisearch server.
|
||||||
|
/// </summary>
|
||||||
void SyncDocumentsToServer();
|
void SyncDocumentsToServer();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously adds a document to the specified repository.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repositoryId">The ID of the repository to add the document to.</param>
|
||||||
|
/// <param name="document">The document to add.</param>
|
||||||
|
/// <param name="autoCommit">If true, automatically syncs the document to the server.</param>
|
||||||
Task AddDocumentAsync(string repositoryId, IDocument document, bool autoCommit = false);
|
Task AddDocumentAsync(string repositoryId, IDocument document, bool autoCommit = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously synchronizes all pending documents to the Meilisearch server.
|
||||||
|
/// </summary>
|
||||||
Task SyncDocumentsToServerAsync();
|
Task SyncDocumentsToServerAsync();
|
||||||
}
|
}
|
@ -2,17 +2,84 @@ using meilisearch.NET.Interfaces;
|
|||||||
|
|
||||||
namespace meilisearch.NET.Services.IndexManagement;
|
namespace meilisearch.NET.Services.IndexManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages Meilisearch index operations including creation, deletion, and storage management.
|
||||||
|
/// </summary>
|
||||||
public interface IIndexManager
|
public interface IIndexManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a list of all index names from the Meilisearch server.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of index names.</returns>
|
||||||
Task<List<string>> GetAllIndexes();
|
Task<List<string>> GetAllIndexes();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously creates a new index with the specified name for the given document type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The document type that implements IDocument.</typeparam>
|
||||||
|
/// <param name="indexName">The name of the index to create.</param>
|
||||||
Task CreateIndexAsync<T>(string indexName) where T : IDocument;
|
Task CreateIndexAsync<T>(string indexName) where T : IDocument;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronously creates a new index with the specified name for the given document type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The document type that implements IDocument.</typeparam>
|
||||||
|
/// <param name="indexName">The name of the index to create.</param>
|
||||||
void CreateIndex<T>(string indexName) where T : IDocument;
|
void CreateIndex<T>(string indexName) where T : IDocument;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously deletes the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexName">The name of the index to delete.</param>
|
||||||
Task DeleteIndexAsync(string indexName);
|
Task DeleteIndexAsync(string indexName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronously deletes the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexName">The name of the index to delete.</param>
|
||||||
void DeleteIndex(string indexName);
|
void DeleteIndex(string indexName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously enables or disables an index by compressing or decompressing it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexName">The name of the index to modify.</param>
|
||||||
|
/// <param name="enabled">True to enable (decompress), false to disable (compress).</param>
|
||||||
Task SetIndexEnabledAsync(string indexName, bool enabled);
|
Task SetIndexEnabledAsync(string indexName, bool enabled);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronously enables or disables an index by compressing or decompressing it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexName">The name of the index to modify.</param>
|
||||||
|
/// <param name="enabled">True to enable (decompress), false to disable (compress).</param>
|
||||||
void SetIndexEnabled(string indexName, bool enabled);
|
void SetIndexEnabled(string indexName, bool enabled);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously gets the storage usage of a specific index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexName">The name of the index.</param>
|
||||||
|
/// <param name="useCompressedSize">If true, returns compressed size for compressed indexes.</param>
|
||||||
|
/// <returns>The storage usage in bytes.</returns>
|
||||||
Task<long> GetIndexStorageUsageAsync(string indexName, bool useCompressedSize = true);
|
Task<long> GetIndexStorageUsageAsync(string indexName, bool useCompressedSize = true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously gets the total storage usage of all indexes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="useCompressedSize">If true, uses compressed sizes for compressed indexes.</param>
|
||||||
|
/// <returns>The total storage usage in bytes.</returns>
|
||||||
Task<long> GetTotalStorageUsageAsync(bool useCompressedSize = true);
|
Task<long> GetTotalStorageUsageAsync(bool useCompressedSize = true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronously gets the storage usage of a specific index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexName">The name of the index.</param>
|
||||||
|
/// <param name="useCompressedSize">If true, returns compressed size for compressed indexes.</param>
|
||||||
|
/// <returns>The storage usage in bytes.</returns>
|
||||||
long GetIndexStorageUsage(string indexName, bool useCompressedSize = true);
|
long GetIndexStorageUsage(string indexName, bool useCompressedSize = true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronously gets the total storage usage of all indexes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="useCompressedSize">If true, uses compressed sizes for compressed indexes.</param>
|
||||||
|
/// <returns>The total storage usage in bytes.</returns>
|
||||||
long GetTotalStorageUsage(bool useCompressedSize = true);
|
long GetTotalStorageUsage(bool useCompressedSize = true);
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Meilisearch;
|
using Meilisearch;
|
||||||
|
using meilisearch.NET.Exceptions;
|
||||||
using meilisearch.NET.Interfaces;
|
using meilisearch.NET.Interfaces;
|
||||||
using meilisearch.NET.Services.ProcessManagement;
|
using meilisearch.NET.Services.ProcessManagement;
|
||||||
using Meilisearch.QueryParameters;
|
using Meilisearch.QueryParameters;
|
||||||
@ -16,35 +17,36 @@ public class IndexManager:IIndexManager
|
|||||||
private readonly string _indexBasePath = Path.Combine(AppContext.BaseDirectory, "db", "indexes" );
|
private readonly string _indexBasePath = Path.Combine(AppContext.BaseDirectory, "db", "indexes" );
|
||||||
private readonly ILogger<IndexManager> _logger;
|
private readonly ILogger<IndexManager> _logger;
|
||||||
private readonly MeilisearchClient _client;
|
private readonly MeilisearchClient _client;
|
||||||
private readonly MeiliSearchProcessManager _processManager;
|
private readonly MeiliSearchProcessManager _meiliSearchProcessManager;
|
||||||
|
|
||||||
public IndexManager(ILogger<IndexManager> logger, MeilisearchClient client, MeiliSearchProcessManager processManager)
|
public IndexManager(ILogger<IndexManager> logger, MeilisearchClient client, MeiliSearchProcessManager meiliSearchProcessManager)
|
||||||
{
|
{
|
||||||
_processManager = processManager;
|
_meiliSearchProcessManager = meiliSearchProcessManager;
|
||||||
_client = client;
|
_client = client;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task<List<string>> GetAllIndexes()
|
public async Task<List<string>> GetAllIndexes()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_logger.LogTrace("Fetching all indexes from Meilisearch server created with the SDK...");
|
||||||
|
var result = _client.GetAllIndexesAsync().Result.Results.Select(x => x.Uid).Where(x=>x!="index_bindings").ToList();
|
||||||
|
_logger.LogInformation($"Fetched {result.Count} indexes from Meilisearch server.");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void CreateIndex<T>(string indexName) where T : IDocument
|
public void CreateIndex<T>(string indexName) where T : IDocument
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var indexes = GetAllIndexes().Result;
|
var indexes = GetAllIndexes().Result;
|
||||||
if(indexes.Count>=1000)
|
if(indexes.Count>=1000)
|
||||||
{
|
throw new IndexLimitReachedException();
|
||||||
_logger.LogWarning("Maximum number of indexes reached, cannot create new index.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indexes.Any(x => x == indexName))
|
if (indexes.Any(x => x == indexName))
|
||||||
{
|
throw new IndexAlreadyExistsException(indexName);
|
||||||
_logger.LogWarning($"Index {indexName} already exists, skipping creation of index.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var foldersBefore = Directory.GetDirectories(_indexBasePath);
|
var foldersBefore = Directory.GetDirectories(_indexBasePath);
|
||||||
_logger.LogTrace($"Creating index '{indexName}'...");
|
_logger.LogTrace($"Creating index '{indexName}'...");
|
||||||
@ -74,18 +76,16 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
public async Task CreateIndexAsync<T>(string indexName) where T : IDocument
|
public async Task CreateIndexAsync<T>(string indexName) where T : IDocument
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var indexes = await GetAllIndexes();
|
var indexes = await GetAllIndexes();
|
||||||
|
|
||||||
if(indexes.Count>=1000)
|
if(indexes.Count>=1000)
|
||||||
{
|
throw new IndexLimitReachedException();
|
||||||
_logger.LogWarning("Maximum number of indexes reached, cannot create new index.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indexes.Any(x => x == indexName))
|
if (indexes.Any(x => x == indexName))
|
||||||
{
|
throw new IndexAlreadyExistsException(indexName);
|
||||||
_logger.LogWarning($"Index {indexName} already exists, skipping creation of index.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var foldersBefore = Directory.GetDirectories(_indexBasePath);
|
var foldersBefore = Directory.GetDirectories(_indexBasePath);
|
||||||
_logger.LogTrace($"Creating index '{indexName}'...");
|
_logger.LogTrace($"Creating index '{indexName}'...");
|
||||||
@ -114,11 +114,13 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
public void DeleteIndex(string indexName)
|
public void DeleteIndex(string indexName)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var indexes = _client.GetAllIndexesAsync().Result;
|
var indexes = _client.GetAllIndexesAsync().Result;
|
||||||
if (indexes.Results.Any(x => x.Uid == indexName)==false)
|
if (indexes.Results.Any(x => x.Uid == indexName)==false)
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Index '{indexName}' does not exist, skipping deletion of index.");
|
throw new IndexNotFoundException(indexName);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_logger.LogTrace($"Deleting index '{indexName}'...");
|
_logger.LogTrace($"Deleting index '{indexName}'...");
|
||||||
_client.DeleteIndexAsync(indexName).Wait();
|
_client.DeleteIndexAsync(indexName).Wait();
|
||||||
@ -127,11 +129,13 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
public async Task DeleteIndexAsync(string indexName)
|
public async Task DeleteIndexAsync(string indexName)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var indexes = _client.GetAllIndexesAsync().Result;
|
var indexes = _client.GetAllIndexesAsync().Result;
|
||||||
if (indexes.Results.Any(x => x.Uid == indexName)==false)
|
if (indexes.Results.Any(x => x.Uid == indexName)==false)
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Index '{indexName}' does not exist, skipping deletion of index.");
|
throw new IndexNotFoundException(indexName);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_logger.LogTrace($"Deleting index '{indexName}'...");
|
_logger.LogTrace($"Deleting index '{indexName}'...");
|
||||||
await _client.DeleteIndexAsync(indexName);
|
await _client.DeleteIndexAsync(indexName);
|
||||||
@ -140,6 +144,9 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
public void SetIndexEnabled(string indexName, bool enabled)
|
public void SetIndexEnabled(string indexName, bool enabled)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
_logger.LogTrace($"Updating index '{indexName}' status to {enabled}...");
|
_logger.LogTrace($"Updating index '{indexName}' status to {enabled}...");
|
||||||
if(enabled)
|
if(enabled)
|
||||||
{
|
{
|
||||||
@ -153,6 +160,9 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
public async Task SetIndexEnabledAsync(string indexName, bool enabled)
|
public async Task SetIndexEnabledAsync(string indexName, bool enabled)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
_logger.LogTrace($"Updating index '{indexName}' status to {enabled}...");
|
_logger.LogTrace($"Updating index '{indexName}' status to {enabled}...");
|
||||||
if(enabled)
|
if(enabled)
|
||||||
{
|
{
|
||||||
@ -166,6 +176,9 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
public long GetIndexStorageUsage(string indexName, bool useCompressedSize = true)
|
public long GetIndexStorageUsage(string indexName, bool useCompressedSize = true)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var doc = _client.GetIndexAsync("index_bindings").Result.GetDocumentAsync<Models.Index>(indexName).Result;
|
var doc = _client.GetIndexAsync("index_bindings").Result.GetDocumentAsync<Models.Index>(indexName).Result;
|
||||||
|
|
||||||
if (doc.IsCompressed)
|
if (doc.IsCompressed)
|
||||||
@ -176,21 +189,22 @@ public class IndexManager:IIndexManager
|
|||||||
var indexPath = GetIndexFilePath(indexName).Result+".zip";
|
var indexPath = GetIndexFilePath(indexName).Result+".zip";
|
||||||
if (!File.Exists(indexPath))
|
if (!File.Exists(indexPath))
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Compressed index not found at: {indexPath}");
|
throw new FileNotFoundException($"Compressed index not found at: {indexPath}");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return new FileInfo(indexPath).Length;
|
return new FileInfo(indexPath).Length;
|
||||||
}
|
}
|
||||||
var path = Path.Combine(_indexBasePath, doc.FolderId);
|
var path = Path.Combine(_indexBasePath, doc.FolderId);
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Index directory not found at: {path}");
|
throw new DirectoryNotFoundException($"Index directory not found at: {path}");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return new DirectoryInfo(path).GetFiles().Sum(f => f.Length);
|
return new DirectoryInfo(path).GetFiles().Sum(f => f.Length);
|
||||||
}
|
}
|
||||||
public long GetTotalStorageUsage(bool useCompressedSize = true)
|
public long GetTotalStorageUsage(bool useCompressedSize = true)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var result = _client.GetIndexAsync("index_bindings").Result.GetDocumentsAsync<Models.Index>(new DocumentsQuery(){Limit = 1000}).Result;
|
var result = _client.GetIndexAsync("index_bindings").Result.GetDocumentsAsync<Models.Index>(new DocumentsQuery(){Limit = 1000}).Result;
|
||||||
var total = 0L;
|
var total = 0L;
|
||||||
foreach (var index in result.Results)
|
foreach (var index in result.Results)
|
||||||
@ -208,6 +222,9 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
public async Task<long> GetIndexStorageUsageAsync(string indexName, bool useCompressedSize = true)
|
public async Task<long> GetIndexStorageUsageAsync(string indexName, bool useCompressedSize = true)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var doc = _client.GetIndexAsync("index_bindings").Result.GetDocumentAsync<Models.Index>(indexName).Result;
|
var doc = _client.GetIndexAsync("index_bindings").Result.GetDocumentAsync<Models.Index>(indexName).Result;
|
||||||
|
|
||||||
if (doc.IsCompressed)
|
if (doc.IsCompressed)
|
||||||
@ -218,21 +235,22 @@ public class IndexManager:IIndexManager
|
|||||||
var indexPath = await GetIndexFilePath(indexName)+".zip";
|
var indexPath = await GetIndexFilePath(indexName)+".zip";
|
||||||
if (!File.Exists(indexPath))
|
if (!File.Exists(indexPath))
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Compressed index not found at: {indexPath}");
|
throw new FileNotFoundException($"Compressed index not found at: {indexPath}");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return new FileInfo(indexPath).Length;
|
return new FileInfo(indexPath).Length;
|
||||||
}
|
}
|
||||||
var path = Path.Combine(_indexBasePath, doc.FolderId);
|
var path = Path.Combine(_indexBasePath, doc.FolderId);
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Index directory not found at: {path}");
|
throw new DirectoryNotFoundException($"Index directory not found at: {path}");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return new DirectoryInfo(path).GetFiles().Sum(f => f.Length);
|
return new DirectoryInfo(path).GetFiles().Sum(f => f.Length);
|
||||||
}
|
}
|
||||||
public async Task<long> GetTotalStorageUsageAsync(bool useCompressedSize = true)
|
public async Task<long> GetTotalStorageUsageAsync(bool useCompressedSize = true)
|
||||||
{
|
{
|
||||||
|
if (!_meiliSearchProcessManager.IsProcessRunning())
|
||||||
|
throw new ProcessNotRunningException();
|
||||||
|
|
||||||
var result = _client.GetIndexAsync("index_bindings").Result.GetDocumentsAsync<Models.Index>(new DocumentsQuery(){Limit = 1000}).Result;
|
var result = _client.GetIndexAsync("index_bindings").Result.GetDocumentsAsync<Models.Index>(new DocumentsQuery(){Limit = 1000}).Result;
|
||||||
var total = 0L;
|
var total = 0L;
|
||||||
foreach (var index in result.Results)
|
foreach (var index in result.Results)
|
||||||
@ -278,8 +296,7 @@ public class IndexManager:IIndexManager
|
|||||||
var indexPath = await GetIndexFilePath(indexName);
|
var indexPath = await GetIndexFilePath(indexName);
|
||||||
if (!Directory.Exists(indexPath))
|
if (!Directory.Exists(indexPath))
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Index directory not found at: {indexPath}");
|
throw new DirectoryNotFoundException($"Index directory not found at: {indexPath}");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var compressedPath = indexPath + ".zip";
|
var compressedPath = indexPath + ".zip";
|
||||||
@ -322,10 +339,9 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError($"Failed to compress index '{indexName}': {ex.Message}");
|
throw new IndexCompressionException(indexName, "compress", ex);
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
_processManager.StopProcess();
|
_meiliSearchProcessManager.StopProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DecompressIndex(string indexName)
|
private async Task DecompressIndex(string indexName)
|
||||||
@ -336,8 +352,7 @@ public class IndexManager:IIndexManager
|
|||||||
|
|
||||||
if (!File.Exists(compressedPath))
|
if (!File.Exists(compressedPath))
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Compressed index not found at: {compressedPath}");
|
throw new FileNotFoundException($"Compressed index not found at: {compressedPath}");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogTrace($"Decompressing index '{indexName}' to {extractPath}...");
|
_logger.LogTrace($"Decompressing index '{indexName}' to {extractPath}...");
|
||||||
@ -379,8 +394,7 @@ public class IndexManager:IIndexManager
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError($"Failed to decompress index '{indexName}': {ex.Message}");
|
throw new IndexCompressionException(indexName, "decompress", ex);
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using meilisearch.NET.Exceptions;
|
||||||
|
using meilisearch.NET.Models;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace meilisearch.NET.Services.ProcessManagement;
|
namespace meilisearch.NET.Services.ProcessManagement;
|
||||||
@ -35,15 +37,21 @@ public abstract class BaseProcessManager : IProcessManager
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError($"Failed to start {GetProcessName()}: {ex.Message}");
|
throw new ProcessStartException(ex,ex.Message);
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void StopProcess()
|
public virtual void StopProcess()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Process?.Kill();
|
Process?.Kill();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Error stopping {GetProcessName()} process: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual bool IsProcessRunning()
|
public virtual bool IsProcessRunning()
|
||||||
{
|
{
|
||||||
|
@ -1,21 +1,33 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using meilisearch.NET.Models;
|
||||||
|
|
||||||
namespace meilisearch.NET.Services.ProcessManagement;
|
namespace meilisearch.NET.Services.ProcessManagement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the contract for managing a process lifecycle and monitoring its resources.
|
||||||
|
/// </summary>
|
||||||
public interface IProcessManager : IDisposable
|
public interface IProcessManager : IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the managed process asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A task representing the asynchronous operation.</returns>
|
||||||
Task StartProcess();
|
Task StartProcess();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the managed process.
|
||||||
|
/// </summary>
|
||||||
void StopProcess();
|
void StopProcess();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the managed process is currently running.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the process is running, false otherwise.</returns>
|
||||||
bool IsProcessRunning();
|
bool IsProcessRunning();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves current resource usage statistics for the managed process.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A ProcessResourceStats object containing resource usage information.</returns>
|
||||||
ProcessResourceStats GetResourceUsage();
|
ProcessResourceStats GetResourceUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ProcessResourceStats
|
|
||||||
{
|
|
||||||
public double CpuPercentage { get; init; }
|
|
||||||
public long MemoryUsageBytes { get; init; }
|
|
||||||
public long DiskReadBytes { get; init; }
|
|
||||||
public long DiskWriteBytes { get; init; }
|
|
||||||
public int ProcessId { get; init; }
|
|
||||||
public int ThreadCount { get; init; }
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user