From f558a9c713a2ddb04585861690dac8df2439a013 Mon Sep 17 00:00:00 2001 From: Gitea Actions Date: Fri, 23 Jan 2026 10:42:45 +0000 Subject: [PATCH] Sync README files from source repository [skip ci] --- README.md | 339 ++++++++++ docs/.gitea/workflows/README.md | 63 ++ docs/src/HttpToSocks5Proxy/README.md | 131 ++++ docs/src/Icomm.API.SmartPool/README.md | 176 +++++ docs/src/Icomm.SmartPool.Proxy/README.md | 790 +++++++++++++++++++++++ docs/src/Icomm.SmartPool.Tests/README.md | 43 ++ 6 files changed, 1542 insertions(+) create mode 100644 README.md create mode 100644 docs/.gitea/workflows/README.md create mode 100644 docs/src/HttpToSocks5Proxy/README.md create mode 100644 docs/src/Icomm.API.SmartPool/README.md create mode 100644 docs/src/Icomm.SmartPool.Proxy/README.md create mode 100644 docs/src/Icomm.SmartPool.Tests/README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..0f6dead --- /dev/null +++ b/README.md @@ -0,0 +1,339 @@ +# Service quản trị Resource trong hệ thống, +- Hỗ trợ 2 giao thức: http(31249), grpc(31287) +- Quản trị 2 resource: proxy pool, token pool + +# ResourcePool Usage Guide + +This guide provides instructions on how to set up and use the **TokenPool** **ProxyPool** in your project. + +--- + +## Installation + +1. Add the following NuGet package references to your project: + ```xml + Icomm.ResourcePool.Abstractions + ``` + ```xml + Icomm.TokenPool + ``` + ```xml + Icomm.ProxyPool + ``` +--- + +## Service Registration + +Register the necessary services in the `Startup.cs` or equivalent service configuration file: + +```csharp +services + .AddConfigManager(hostContext.Configuration) + .AddTokenPool( + hostContext.Configuration, + opt => + { +#if DEBUG + opt.Host = "10.9.3.70"; + opt.protocol = ResourcePool.Core.Protocol.Grpc; + opt.Port = 31287; +#endif + } + ) + .AddProxyPool( + hostContext.Configuration, + opt => + { +#if DEBUG + opt.Host = "10.9.3.70"; + opt.protocol = ResourcePool.Core.Protocol.Grpc; + opt.Port = 31287; +#endif + } + ) + ; +``` + +--- + +## Usage TokenPool + +Once the services are registered, you can inject and use the `ITokenPoolService` in your application. + +### Example: +```csharp +private readonly ITokenPoolService _tokenPoolService; + +public MyService(ITokenPoolService tokenPoolService) +{ + _tokenPoolService = tokenPoolService; +} +// example with EstimateRequest +public async Task UseTokenPool() +{ + // Example usage of the _tokenPoolService + var token = await _tokenPoolService.RequestToken( + new TokenRequest() + { + EstimateRequest = 1, + Action = action, + Platform = "1", + } + ); + Console.WriteLine($"Retrieved Token: {token}"); +} +// example withouy EstimateRequest +public async Task UseTokenPool() +{ + // Example usage of the _tokenPoolService + var token = await _tokenPoolService.RequestToken( + new TokenRequest() + { + Action = action, + Platform = "1", + } + ); + await _tokenPoolService.UsedToken(token); + Console.WriteLine($"Retrieved Token: {token}"); +} +``` + +- The `ITokenPoolService` provides methods to interact with the Token Pool. +- Ensure that the service is properly registered and injected where needed. + +--- + +## Usage ProxyPool + +Once the services are registered, you can inject and use the `IProxyPoolService` in your application. + +### Example: +```csharp +private readonly IProxyPoolService _proxyPool;; + +public MyService(IProxyPoolService proxyPool) +{ + _proxyPool = proxyPool; +} +// example with EstimateRequest +public async Task UseProxyPoolWithRestSharp() +{ + // Example usage of the _tokenPoolService + var proxy = await _proxyPool.GetProxyServerAsync( + cancellationToken: cancellationToken + ); + var clientOptions = new RestClientOptions(url) + { + Proxy = proxy + }; + Console.WriteLine($"Retrieved Token: {token}"); +} + +// example with EstimateRequest +public async Task UseRawProxyPoolWithRestSharp() +{ + // Example usage of the _tokenPoolService + var proxy = await _proxyPool.GetRawProxyServerAsync( + cancellationToken: cancellationToken + ); + var clientOptions = new RestClientOptions(url) + { + Proxy = new WebProxy(proxy.Host, proxy.Port) + }; + Console.WriteLine($"Retrieved Token: {token}"); +} +``` + +- The `ITokenPoolService` `IProxyPoolService` provides methods to interact with the Token Pool. +- Ensure that the service is properly registered and injected where needed. + +--- + +## Notes + +- The `opt.Host`, `opt.Protocol`, and `opt.Port` configuration should match your environment settings. +- In production, replace the debug configurations with the appropriate production values. + +--- + +## API Documentation + +### Proxy Pool API - GetProxyByFeature + +Endpoint: `POST /api/resource-pool/v1/ProxyPool/get-v2` + +Lấy proxy server theo features và chiến lược lọc cụ thể. + +#### 📋 Request Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `target_domain` | string | Optional | Domain đích cần truy cập (vd: facebook.com, x.com) | +| `type` | string | **Required** | Loại proxy ("http", "httpv6", "socks") | +| `country` | string | Optional | Mã quốc gia proxy ("VN", "US", "JP") | +| `strategy` | string | **Required** | Chiến lược chọn proxy | +| `referer_proxy` | object | Optional | Proxy tham chiếu để tìm proxy thay thế tốt nhất | + +#### ⚠️ Logic Ưu Tiên Tham Số + +**Nếu `referer_proxy.id` khác null**: Hệ thống sẽ ưu tiên lấy thông tin từ proxy referer làm tham số lọc chính, sau đó mới sử dụng các tham số `type`, `country`, `target_domain` để lọc bổ sung. + +**Cách hoạt động**: +1. **Bước 1**: Hệ thống lấy thông tin của proxy có ID = `referer_proxy.id` +2. **Bước 2**: Sử dụng thông tin proxy đó (type, country, location) làm tiêu chí lọc chính +3. **Bước 3**: Áp dụng các tham số `type`, `country`, `target_domain` như điều kiện lọc bổ sung +4. **Bước 4**: Thực hiện strategy được chọn trên pool đã được lọc + +**Lợi ích**: +- Tìm proxy thay thế có đặc tính tương tự với proxy đang sử dụng +- Đảm bảo tính nhất quán trong quality và performance +- Hỗ trợ thuật toán fallback khi proxy hiện tại gặp vấn đề + +#### 🎯 Available Strategies + +##### 1. 🎲 Random Strategy (`strategy: "random"`) +- **Tham số bắt buộc**: `type` +- **Tham số tùy chọn**: `country` +- **Mô tả**: Chọn ngẫu nhiên proxy từ pool phù hợp +- **Ví dụ**: +```json +{ + "type": "httpv6", + "strategy": "random", + "country": "VN" +} +``` + +##### 2. ⚖️ Round Robin Strategy (`strategy: "round_robin"`) +- **Tham số bắt buộc**: `type` +- **Tham số tùy chọn**: `country` +- **Mô tả**: Phân phối request đều khắp các proxy trong pool +- **Ví dụ**: +```json +{ + "type": "http", + "strategy": "round_robin", + "country": "US" +} +``` + +##### 3. 📊 Least Used Strategy (`strategy: "least_used"`) +- **Tham số bắt buộc**: `referer_proxy.id` +- **Mô tả**: Chọn proxy có tần suất sử dụng thấp nhất +- **Logic đặc biệt**: Sử dụng thông tin referer_proxy làm tham số lọc chính +- **Ví dụ**: +```json +{ + "strategy": "least_used", + "referer_proxy": { + "id": 123 + }, + "type": "httpv6", + "country": "VN" +} +``` + +##### 4. ⚡ Least Delay Strategy (`strategy: "least_delay"`) +- **Tham số bắt buộc**: `target_domain`, `type` +- **Tham số tùy chọn**: `country` +- **Mô tả**: Chọn proxy có độ trễ thấp nhất cho domain cụ thể +- **Ví dụ**: +```json +{ + "target_domain": "facebook.com", + "type": "httpv6", + "strategy": "least_delay", + "country": "US" +} +``` + +##### 5. 🏆 Adaptive Ranking Strategy (`strategy: "adaptive_ranking"`) +- **Tham số bắt buộc**: `target_domain`, `type` +- **Tham số tùy chọn**: `country` +- **Mô tả**: Chọn proxy có điểm số cao nhất (tỷ lệ thành công + tốc độ response) +- **Ví dụ**: +```json +{ + "target_domain": "instagram.com", + "type": "http", + "strategy": "adaptive_ranking", + "country": "JP" +} +``` + +#### 📤 Response Format + +```json +{ + "proxy": { + "id": 123, + "host": "192.168.1.100", + "port": 8080, + "type": "httpv6", + "country": "VN", + "location": "Ho Chi Minh City", + "status": 1, + "auth_username": "user", + "auth_password": "password", + "cluster": "cluster1", + "source": "manual", + "updateTime": "2024-01-15T10:30:00Z" + } +} +``` + +#### 🔧 Example Usage + +**Sử dụng với HttpClient:** +```csharp +var request = new ProxyRequestByFeature +{ + Type = "httpv6", + Strategy = "adaptive_ranking", + TargetDomain = "facebook.com", + Country = "VN" +}; + +var response = await httpClient.PostAsJsonAsync( + "/api/resource-pool/v1/ProxyPool/get-v2", + request +); + +var proxyData = await response.Content.ReadFromJsonAsync(); + +// Sử dụng proxy với HttpClient +var httpClient = new HttpClient(); +httpClient.DefaultRequestHeaders.Add("Proxy", + $"http://{proxyData.Proxy.AuthUsername}:{proxyData.Proxy.AuthPassword}@{proxyData.Proxy.Host}:{proxyData.Proxy.Port}"); +``` + +**Sử dụng với RestSharp:** +```csharp +var request = new RestRequest("/api/resource-pool/v1/ProxyPool/get-v2", Method.Post); +request.AddJsonBody(new ProxyRequestByFeature +{ + Type = "http", + Strategy = "least_delay", + TargetDomain = "instagram.com", + Country = "US" +}); + +var response = await client.ExecuteAsync(request); +var proxy = new WebProxy($"{response.Data.Proxy.Host}:{response.Data.Proxy.Port}") +{ + Credentials = new NetworkCredential(response.Data.Proxy.AuthUsername, response.Data.Proxy.AuthPassword) +}; + +var restClient = new RestClient("https://api.example.com") +{ + Proxy = proxy +}; +``` + +--- + + +## Proxy Pool Diagram +![Proxy Pool Diagram](Diagram-Proxy.png) +## Token Pool Diagram +![Token Pool Diagram](Diagram-Token.png) \ No newline at end of file diff --git a/docs/.gitea/workflows/README.md b/docs/.gitea/workflows/README.md new file mode 100644 index 0000000..a0f51dd --- /dev/null +++ b/docs/.gitea/workflows/README.md @@ -0,0 +1,63 @@ +# Gitea Actions - Sync README Files + +Workflow này tự động đồng bộ các file README.md từ repository này sang một repository công khai khác. + +## Cấu hình + +### 1. Thiết lập Secrets trong Gitea + +Vào **Settings > Secrets** của repository và thêm 2 secrets sau: + +- `TARGET_REPO_URL`: URL của repository đích (ví dụ: `https://gitea.example.com/username/public-repo.git`) +- `TOKEN_ACTION_PUBLIC_README`: Token có quyền push vào repository đích + +### 2. Tạo Token trong Gitea + +1. Vào **Settings > Applications > Generate New Token** +2. Đặt tên token (ví dụ: "README Sync Token") +3. Chọn quyền: `write:repository` hoặc `repo` +4. Copy token và lưu vào secret `TOKEN_ACTION_PUBLIC_README` + +### 3. Cách hoạt động + +Workflow sẽ tự động chạy khi: +- **Push events**: Có push vào các branch `main` hoặc `master` (sau khi PR được merge) +- **Pull Request events**: Có PR mới, cập nhật, hoặc reopen vào `main`/`master` với thay đổi file `.md` +- **Manual trigger**: Chạy thủ công qua **Actions > Sync README files > Run workflow** + +**Lưu ý quan trọng:** +- Khi chạy trên **PR event**: Workflow sẽ validate và chuẩn bị files nhưng **KHÔNG push** vào repo đích (chỉ để preview) +- Khi chạy trên **Push event** (sau khi merge): Workflow sẽ **push** files vào repo đích + +### 4. Cấu trúc file được sync + +- File `readme.md` hoặc `README.md` ở root → được copy thành `README.md` ở root của repo đích +- Các file `README.md` trong các thư mục con → được copy vào `docs/` của repo đích, giữ nguyên cấu trúc thư mục + +### 5. Kiểm tra kết quả + +Sau khi workflow chạy: +- Vào tab **Actions** để xem log +- Kiểm tra repository đích để xác nhận các file đã được sync + +## Troubleshooting + +### Lỗi: "TARGET_REPO_URL secret is not set" +- Kiểm tra đã thêm secret `TARGET_REPO_URL` chưa +- Đảm bảo tên secret chính xác (case-sensitive) + +### Lỗi: "Failed to clone target repository" +- Kiểm tra URL repository đích có đúng không +- Kiểm tra token có quyền đọc repository không +- Đảm bảo repository đích là public hoặc token có quyền truy cập + +### Lỗi: "Push failed" +- Kiểm tra token có quyền push vào repository đích +- Kiểm tra branch mặc định của repository đích (main/master) + +## Tùy chỉnh + +Nếu cần thay đổi: +- **Branch trigger**: Sửa phần `branches` trong workflow +- **File pattern**: Sửa phần `paths` trong workflow +- **Target directory**: Sửa phần copy files trong step "Find and copy README files" diff --git a/docs/src/HttpToSocks5Proxy/README.md b/docs/src/HttpToSocks5Proxy/README.md new file mode 100644 index 0000000..dd49199 --- /dev/null +++ b/docs/src/HttpToSocks5Proxy/README.md @@ -0,0 +1,131 @@ +# HttpToSocks5Proxy - .NET 8.0 + +HTTP(S) to SOCKS5 proxy adapter for .NET 8.0 + +## Overview + +This library implements `IWebProxy` interface to act as an HTTP(S) proxy while connecting to a SOCKS5 server behind the scenes. It has been upgraded from .NET Standard 2.0 to .NET 8.0 for better performance and modern features. + +## Features + +- ✅ Implements `IWebProxy` interface +- ✅ Transparent HTTP to SOCKS5 conversion +- ✅ Support for authentication +- ✅ Custom DNS resolver support +- ✅ .NET 8.0 optimizations +- ✅ Nullable reference types enabled + +## Usage + +### Basic Usage + +```csharp +using SockNet; + +// Create proxy without authentication +var proxy = new HttpToSocks5Proxy("socks5-server.com", 1080); + +// Use with HttpClient +var handler = new HttpClientHandler { Proxy = proxy }; +var httpClient = new HttpClient(handler); + +var response = await httpClient.GetAsync("https://example.com"); +``` + +### With Authentication + +```csharp +// Create proxy with SOCKS5 authentication +var proxy = new HttpToSocks5Proxy( + "socks5-server.com", + 1080, + "username", + "password" +); + +var handler = new HttpClientHandler { Proxy = proxy }; +var httpClient = new HttpClient(handler); +``` + +### With SmartPool + +```csharp +using Icomm.SmartPool.Abstractions.Responses; + +var proxyServer = new SmartProxyServer +{ + host = "socks5-server.com", + port = 1080, + protocol = "socks5", + auth_username = "user", + auth_password = "pass" +}; + +// Convert to IWebProxy +var webProxy = proxyServer.ToWebProxy(); + +// Use with HttpClient +var handler = new HttpClientHandler { Proxy = webProxy }; +var httpClient = new HttpClient(handler); +``` + +## Upgrade Notes + +### Changes from Previous Version + +- **Target Framework**: Changed from `netstandard2.0;net45` to `net8.0` +- **Version**: Bumped to `2.0.0` +- **Language Features**: Enabled nullable reference types +- **Performance**: Benefits from .NET 8.0 runtime improvements + +### Breaking Changes + +- Minimum requirement is now .NET 8.0 +- No longer supports .NET Framework 4.5 or .NET Standard 2.0 + +## Integration with SmartPool + +This library is used by SmartPool system to support SOCKS5 proxies: + +``` +SmartPool Client + ↓ +SmartProxyServer.ToWebProxy() + ↓ +HttpToSocks5Proxy (if protocol is socks5) + ↓ +SOCKS5 Server + ↓ +Target Website +``` + +## Technical Details + +### Namespace + +- Root namespace: `SockNet` +- Assembly name: `SockNet.HttpToSocks5Proxy` + +### Dependencies + +- .NET 8.0 Runtime +- No external NuGet packages required + +## License + +MIT License + +## Version History + +- **2.0.0** (2026-01-22) + - Upgraded to .NET 8.0 + - Enabled nullable reference types + - Added modern C# language features + +- **1.4.0** (Previous) + - .NET Standard 2.0 / .NET Framework 4.5 + - Original implementation + +## Support + +For issues related to SmartPool integration, see the main SmartPool documentation. diff --git a/docs/src/Icomm.API.SmartPool/README.md b/docs/src/Icomm.API.SmartPool/README.md new file mode 100644 index 0000000..23a03a3 --- /dev/null +++ b/docs/src/Icomm.API.SmartPool/README.md @@ -0,0 +1,176 @@ +# Icomm.API.SmartPool + +SmartPool API Backend - Intelligent proxy management system with multiple selection strategies. + +## Features + +- **Multiple Selection Strategies**: + - Random: Random selection from available proxies + - Round Robin: Balanced distribution across proxies + - Least Delay: Select fastest proxy based on response time + - Adaptive Ranking: Select proxy with highest success rate + - Alternative: Find similar proxy to replace failed one + +- **Dual Protocol Support**: + - gRPC (MagicOnion) for high-performance RPC + - HTTP REST API for standard web clients + +- **ClickHouse Integration**: + - High-performance logging + - Real-time analytics + - Automatic aggregation with materialized views + +## Troubleshooting + +### "No proxy available matching criteria" + +If you get this error, check: + +1. **Run initialization script:** + ```bash + clickhouse-client < clickhouse_init.sql + ``` + +2. **Add test data:** + ```bash + clickhouse-client < clickhouse_test_data.sql + ``` + +3. **Debug the issue:** + ```bash + clickhouse-client < clickhouse_debug.sql + ``` + +4. **Verify your access_token has mappings:** + ```sql + SELECT * FROM smart_pool_meta.proxy_access_mapping FINAL + WHERE access_token = 'YOUR_TOKEN'; + ``` + +5. **Verify proxies exist in those clusters:** + ```sql + SELECT m.* + FROM smart_pool_meta.proxy_metadata FINAL m + INNER JOIN smart_pool_meta.proxy_access_mapping FINAL a + ON m.cluster = a.cluster + WHERE a.access_token = 'YOUR_TOKEN' + AND m.status = 1; + ``` + +### Common Issues + +1. **Empty database**: Run `clickhouse_init.sql` and `clickhouse_test_data.sql` +2. **No access mapping**: Your access_token needs to be mapped to clusters +3. **All proxies inactive**: Check `status = 1` in proxy_metadata +4. **Wrong cluster names**: Ensure cluster names match between metadata and mappings + +## Quick Start + +### 1. Setup ClickHouse + +```bash +# Run ClickHouse initialization script +clickhouse-client < clickhouse_init.sql +``` + +### 2. Configure Settings + +Edit `appsettings.json`: + +```json +{ + "ClickHouse": { + "Host": "localhost", + "Port": 8123, + "Database": "smart_pool", + "Username": "default", + "Password": "" + }, + "Redis": { + "Configuration": "localhost:6379" + } +} +``` + +### 3. Run the API + +```bash +dotnet run +``` + +The API will be available at: +- HTTP: `http://localhost:5000` +- gRPC: `http://localhost:5001` +- Swagger UI: `http://localhost:5000/swagger` + +## API Endpoints + +### Get Proxy + +**POST** `/api/smart-pool/v1/SmartProxy/get-proxy` + +```json +{ + "access_token": "your-token", + "strategy": "least_delay", + "target_domain": "facebook.com", + "ipVersion": "v6", + "protocol": "http", + "country": "US" +} +``` + +### Log Usage + +**POST** `/api/smart-pool/v1/SmartProxy/log-usage` + +```json +{ + "access_token": "your-token", + "proxy_id": 123, + "target_domain": "facebook.com", + "status_code": 200, + "response_time_ms": 450 +} +``` + +## gRPC Usage + +```csharp +var channel = GrpcChannel.ForAddress("http://localhost:5001"); +var client = MagicOnionClient.Create(channel); + +var response = await client.GetProxy(new GetProxyRequest +{ + access_token = "your-token", + strategy = "adaptive_ranking" +}); +``` + +## Architecture + +``` +Client Request + ↓ +API Layer (gRPC/HTTP) + ↓ +Strategy Factory + ↓ +Strategy Implementation + ↓ +Repository Layer + ↓ +ClickHouse Database +``` + +## Dependencies + +- .NET 8.0 +- MagicOnion.Server 5.1.11 +- ClickHouse.Client 7.7.0 +- EasyCaching.Redis 1.9.2 +- Serilog + +## License + +Internal use only. diff --git a/docs/src/Icomm.SmartPool.Proxy/README.md b/docs/src/Icomm.SmartPool.Proxy/README.md new file mode 100644 index 0000000..a539b27 --- /dev/null +++ b/docs/src/Icomm.SmartPool.Proxy/README.md @@ -0,0 +1,790 @@ +# Icomm.SmartPool.Proxy + +Client SDK for SmartPool proxy management system. Supports both gRPC and HTTP protocols. + +> 📖 **Xem tài liệu chi tiết**: [SDK_DOCUMENTATION.md](./SDK_DOCUMENTATION.md) + +## ✨ Features + +- ✅ **Dual Protocol**: gRPC (MagicOnion) và HTTP REST API +- ✅ **5 Chiến lược**: Random, Round Robin, Least Delay, Adaptive Ranking, Alternative +- ✅ **Tối ưu hiệu suất**: Keep-alive, Connection pooling, Client caching, Compression +- ✅ **Batch Logging**: Ghi log hiệu quả với batch processing +- ✅ **Fire-and-Forget**: Non-blocking logging +- ✅ **Compact Response**: Giảm payload size ~50-60% + +## Installation + +### Prerequisites + +Đảm bảo bạn đã cấu hình NuGet source `ic` trong project: + +```bash +# Thêm NuGet source (nếu chưa có) +dotnet nuget add source --name ic +``` + +### Install via NuGet Package + +Cài đặt package từ NuGet repository: + +```bash +dotnet add package --source ic --version 10.0.1 Icomm.SmartPool.Proxy +``` + +Hoặc thêm vào `.csproj` file: + +```xml + + + +``` + +Và cấu hình NuGet source trong `nuget.config`: + +```xml + + + + + + +``` + +## Quick Start + +### Configuration + +Add to `appsettings.json`: + +```json +{ + "SmartPool": { + "Protocol": "Grpc", + "Host": "localhost", + "Port": 5001, + "UseSecureConnection": false, + "DefaultAccessToken": "your-access-token", + "TimeoutMs": 30000 + } +} +``` + +### Register in DI Container + +```csharp +using Icomm.SmartPool.Proxy.Extensions; + +// In Startup.cs or Program.cs +services.AddSmartPoolClient(configuration); +``` + +### Use in Your Code + +```csharp +public class MyService +{ + private readonly ISmartPoolClient _smartPoolClient; + + public MyService(ISmartPoolClient smartPoolClient) + { + _smartPoolClient = smartPoolClient; + } + + public async Task MakeRequestAsync() + { + // Get proxy as IWebProxy (ready for HttpClient) + var proxy = await _smartPoolClient.GetProxyAsync( + strategy: "least_delay", + targetDomain: "facebook.com", + ipVersion: "v6" + ); + + if (proxy != null) + { + var handler = new HttpClientHandler { Proxy = proxy }; + var httpClient = new HttpClient(handler); + + var response = await httpClient.GetAsync("https://facebook.com"); + + // Log usage + await _smartPoolClient.LogProxyUsageAsync( + accessToken: "your-token", + proxyId: 123, + targetDomain: "facebook.com", + statusCode: (int)response.StatusCode, + responseTimeMs: 450 + ); + } + } +} +``` + +## Advanced Usage + +### Get Raw Proxy Information + +```csharp +var request = new GetProxyRequest +{ + access_token = "your-token", + strategy = "adaptive_ranking", + target_domain = "facebook.com", + ip_version = "v6", + protocol = "http", + country = "US" +}; + +var proxyServer = await _smartPoolClient.GetRawProxyAsync(request); + +if (proxyServer != null) +{ + Console.WriteLine($"Proxy: {proxyServer.host}:{proxyServer.port}"); + Console.WriteLine($"Country: {proxyServer.country}"); +} +``` + +### Alternative Proxy Strategy + +```csharp +var request = new GetProxyRequest +{ + access_token = "your-token", + strategy = "alternative", + referer_proxy = new SmartProxyServer { id = 123 } // Current proxy that failed +}; + +var alternativeProxy = await _smartPoolClient.GetRawProxyAsync(request); +``` + +## Strategies + +- **random**: Random selection +- **round_robin**: Balanced distribution +- **least_delay**: Fastest proxy (requires targetDomain) +- **adaptive_ranking**: Highest success rate (requires targetDomain) +- **alternative**: Similar proxy replacement (requires refererProxy) + +## Protocol Selection + +### gRPC (Recommended) + +```csharp +services.AddSmartPoolClient(options => +{ + options.Protocol = SmartPoolProtocol.Grpc; + options.Host = "api.example.com"; + options.Port = 5001; +}); +``` + +**Pros**: High performance, binary protocol, streaming support + +### HTTP + +```csharp +services.AddSmartPoolClient(options => +{ + options.Protocol = SmartPoolProtocol.Http; + options.Host = "api.example.com"; + options.Port = 5000; +}); +``` + +**Pros**: Standard REST API, easier debugging, firewall-friendly + +## Error Handling + +SDK cung cấp exception handling chi tiết với các exception types tương ứng với error codes từ server: + +### Exception Types + +```csharp +using Icomm.SmartPool.Proxy.Exceptions; + +try +{ + var proxy = await _smartPoolClient.GetRawProxyAsync(request); + // Use proxy... +} +catch (AccessTokenRequiredException) +{ + // Access token không được cung cấp + Console.WriteLine("Access token is required"); +} +catch (AccessTokenInvalidException ex) +{ + // Access token không hợp lệ hoặc không được phân quyền + Console.WriteLine($"Invalid access token: {ex.AccessToken}"); +} +catch (NoAvailableProxiesException ex) +{ + // Không có proxy available cho access token này + Console.WriteLine($"No proxies available for token: {ex.AccessToken}"); +} +catch (NoMatchingProxiesException) +{ + // Không có proxy match với filters (ip_version, protocol, country, etc.) + Console.WriteLine("No proxies match the specified filters"); +} +catch (StrategyNotFoundException ex) +{ + // Strategy không tồn tại + Console.WriteLine($"Strategy not found: {ex.StrategyName}"); +} +catch (RefererProxyRequiredException) +{ + // Alternative strategy cần referer_proxy + Console.WriteLine("Referer proxy is required for alternative strategy"); +} +catch (SmartPoolException ex) +{ + // Các lỗi khác từ SmartPool + Console.WriteLine($"SmartPool error ({ex.ErrorCode}): {ex.Message}"); +} +catch (Exception ex) +{ + // Network errors, timeout, etc. + Console.WriteLine($"Network error: {ex.Message}"); +} +``` + +### Try Methods (Không Throw Exception) + +SDK cung cấp các method `Try*` để bỏ qua exceptions và trả về `null` nếu lỗi: + +```csharp +// TryGetRawProxyAsync - không throw exception +var proxy = await _smartPoolClient.TryGetRawProxyAsync(request); +if (proxy != null) +{ + // Sử dụng proxy + Console.WriteLine($"Proxy: {proxy.host}:{proxy.port}"); +} +else +{ + // Xử lý khi không lấy được proxy (silent failure) + Console.WriteLine("Failed to get proxy"); +} + +// TryGetProxyAsync - không throw exception +var webProxy = await _smartPoolClient.TryGetProxyAsync(request); +if (webProxy != null) +{ + var handler = new HttpClientHandler { Proxy = webProxy }; + var httpClient = new HttpClient(handler); + // Use httpClient... +} +``` + +**Khi nào dùng Try methods:** +- Khi bạn muốn xử lý lỗi một cách silent (không cần biết chi tiết lỗi) +- Trong retry logic, khi bạn chỉ cần biết success/failure +- Khi performance quan trọng hơn error details + +## Health Check + +```csharp +var isHealthy = await _smartPoolClient.PingAsync(); +if (!isHealthy) +{ + Console.WriteLine("SmartPool API is not responding"); +} +``` + +## Performance Optimizations + +SDK đã được tối ưu với các tính năng: + +- **Connection Pooling & Keep-Alive**: Giảm latency reconnect từ ~50-100ms xuống ~5ms +- **Client-side Caching**: Giảm network calls ~90% khi cache hit +- **Response Compression**: Giảm payload size ~30-50% +- **Batch Logging**: Giảm N network calls → 1 call +- **Fire-and-Forget**: Non-blocking logging, không block main flow + +Xem chi tiết trong [SDK_DOCUMENTATION.md](./SDK_DOCUMENTATION.md#tối-ưu-hiệu-suất). + +## Chi Tiết Các Modes và Cách Hoạt Động + +### 1. Protocol Modes + +#### gRPC Mode (Khuyến nghị) + +**Cách hoạt động:** +- Sử dụng HTTP/2 với binary protocol (MessagePack) +- Connection pooling tự động với keep-alive +- Compression tự động (gzip/deflate) +- Streaming support cho batch operations + +**Cấu hình:** +```json +{ + "SmartPool": { + "Protocol": "Grpc", + "Host": "api.example.com", + "Port": 5001, + "UseSecureConnection": true, + "EnableCompression": true, + "CompressionAlgorithm": "gzip" + } +} +``` + +**Khi nào dùng:** +- ✅ High-performance scenarios (scraping, batch processing) +- ✅ Internal services (microservices communication) +- ✅ Khi cần throughput cao +- ✅ Khi có control over network (không bị firewall block HTTP/2) + +**Ưu điểm:** +- Performance cao hơn HTTP ~30-50% +- Binary protocol → payload nhỏ hơn +- Connection pooling tự động +- Keep-alive giảm latency + +**Nhược điểm:** +- Cần HTTP/2 support +- Khó debug hơn (binary format) +- Có thể bị firewall block + +#### HTTP Mode + +**Cách hoạt động:** +- Standard HTTP/1.1 REST API +- JSON serialization +- Standard HttpClient với connection pooling +- Dễ debug với browser DevTools + +**Cấu hình:** +```json +{ + "SmartPool": { + "Protocol": "Http", + "Host": "api.example.com", + "Port": 5000, + "UseSecureConnection": true + } +} +``` + +**Khi nào dùng:** +- ✅ External clients (web browsers, mobile apps) +- ✅ Khi cần debug dễ dàng +- ✅ Khi firewall chỉ cho phép HTTP +- ✅ Development/testing environments + +**Ưu điểm:** +- Dễ debug (JSON, có thể test với Postman/curl) +- Universal support (mọi client đều hỗ trợ HTTP) +- Firewall-friendly +- Standard REST API + +**Nhược điểm:** +- Performance thấp hơn gRPC +- Payload lớn hơn (JSON vs binary) +- Không có streaming support + +### 2. Client-Side Caching Mode + +**Cách hoạt động:** +- Cache proxy results trong memory (MemoryCache) +- Cache key dựa trên: access_token, strategy, filters (ip_version, protocol, country, target_domain) +- TTL: `ClientCacheDurationSeconds` (default: 30s) +- Sliding expiration: 50% của TTL +- Max entries: `ClientCacheMaxEntries` (default: 100) + +**Flow:** +``` +1. Request proxy với filters +2. Check cache → Cache hit? Return cached proxy +3. Cache miss? Call API → Cache result → Return proxy +4. Next request với same filters → Return từ cache (không call API) +``` + +**Cấu hình:** +```json +{ + "SmartPool": { + "EnableClientCache": true, + "ClientCacheDurationSeconds": 30, + "ClientCacheMaxEntries": 100 + } +} +``` + +**Khi nào dùng:** +- ✅ Khi request cùng filters nhiều lần +- ✅ Random/Round-robin strategies (không phụ thuộc vào real-time data) +- ✅ Giảm load cho API server +- ✅ Giảm latency cho client + +**Khi KHÔNG nên dùng:** +- ❌ Least Delay strategy (cần real-time data) +- ❌ Adaptive Ranking strategy (cần real-time data) +- ❌ Khi cần proxy mới mỗi lần request + +**Ví dụ:** +```csharp +// Request 1: Call API, cache result +var proxy1 = await _client.GetProxyAsync(new GetProxyRequest +{ + strategy = "random", + ip_version = "v6" +}); + +// Request 2: Return từ cache (không call API) +var proxy2 = await _client.GetProxyAsync(new GetProxyRequest +{ + strategy = "random", + ip_version = "v6" +}); +// proxy1 và proxy2 giống nhau (cùng từ cache) + +// Request 3: Khác filters → Call API mới +var proxy3 = await _client.GetProxyAsync(new GetProxyRequest +{ + strategy = "random", + ip_version = "v4" // Khác filter +}); +``` + +### 3. Logging Modes + +#### Fire-and-Forget Mode + +**Cách hoạt động:** +- Logging chạy trong background task (không block main thread) +- Nếu có batch logging → Queue vào channel +- Nếu không có batch → Fire task riêng +- Không đợi response từ server + +**Cấu hình:** +```json +{ + "SmartPool": { + "EnableFireAndForgetLogging": true + } +} +``` + +**Khi nào dùng:** +- ✅ High-throughput scenarios +- ✅ Khi logging không critical (best-effort) +- ✅ Khi không muốn block main flow +- ✅ Background processing + +**Ví dụ:** +```csharp +// Non-blocking - không đợi response +await _client.LogProxyUsageAsync(new ProxyUsageLogRequest +{ + proxy_id = 123, + status_code = 200, + response_time_ms = 450 +}); +// Code tiếp tục chạy ngay, không đợi log complete +``` + +#### Batch Logging Mode + +**Cách hoạt động:** +- Queue log requests vào bounded channel +- Background task collect logs theo batch +- Flush khi đạt `LogBatchSize` hoặc `LogBatchFlushIntervalMs` +- Gửi batch đến server + +**Flow:** +``` +1. LogProxyUsageAsync() → Queue vào channel +2. Background task collect logs +3. Khi đủ LogBatchSize (50) hoặc timeout (5s) → Flush batch +4. Gửi batch đến server +``` + +**Cấu hình:** +```json +{ + "SmartPool": { + "EnableBatchLogging": true, + "LogBatchSize": 50, + "LogBatchFlushIntervalMs": 5000 + } +} +``` + +**Khi nào dùng:** +- ✅ High-throughput scenarios (1000+ requests/second) +- ✅ Khi muốn giảm network calls +- ✅ Khi có nhiều logs cần gửi + +**Ví dụ:** +```csharp +// Queue 1000 logs +for (int i = 0; i < 1000; i++) +{ + _client.QueueLogProxyUsage(new ProxyUsageLogRequest + { + proxy_id = i, + status_code = 200, + response_time_ms = 450 + }); +} +// Chỉ gửi ~20 batches (50 logs/batch) thay vì 1000 requests +``` + +**Kết hợp Fire-and-Forget + Batch:** +```json +{ + "SmartPool": { + "EnableFireAndForgetLogging": true, + "EnableBatchLogging": true, + "LogBatchSize": 50, + "LogBatchFlushIntervalMs": 5000 + } +} +``` +→ Logging hoàn toàn non-blocking và batch processing + +#### Synchronous Logging Mode + +**Cách hoạt động:** +- Đợi response từ server +- Block cho đến khi log complete +- Throw exception nếu lỗi + +**Cấu hình:** +```json +{ + "SmartPool": { + "EnableFireAndForgetLogging": false, + "EnableBatchLogging": false + } +} +``` + +**Khi nào dùng:** +- ✅ Khi logging là critical (cần đảm bảo log được gửi) +- ✅ Low-throughput scenarios +- ✅ Debug/testing + +**Ví dụ:** +```csharp +// Blocking - đợi response +var success = await _client.LogProxyUsageAsync(new ProxyUsageLogRequest +{ + proxy_id = 123, + status_code = 200 +}); +if (!success) +{ + // Handle failure +} +``` + +### 4. Connection Pooling & Keep-Alive Mode + +**Cách hoạt động:** + +**gRPC:** +- HTTP/2 connection pooling tự động +- Keep-alive ping mỗi `KeepAlivePingDelaySeconds` (60s) +- Ping timeout: `KeepAlivePingTimeoutSeconds` (30s) +- Connection idle timeout: `PooledConnectionIdleTimeoutMinutes` (5min) +- Connection lifetime: `PooledConnectionLifetimeMinutes` (10min) + +**HTTP:** +- HttpClient connection pooling +- Connection idle timeout: `PooledConnectionIdleTimeoutMinutes` (5min) +- Connection lifetime: `PooledConnectionLifetimeMinutes` (10min) + +**Cấu hình:** +```json +{ + "SmartPool": { + "KeepAlivePingDelaySeconds": 60, + "KeepAlivePingTimeoutSeconds": 30, + "PooledConnectionIdleTimeoutMinutes": 5, + "PooledConnectionLifetimeMinutes": 10, + "EnableMultipleHttp2Connections": true, + "ConnectTimeoutSeconds": 5 + } +} +``` + +**Lợi ích:** +- Giảm latency: Reuse connection thay vì tạo mới (~50-100ms → ~5ms) +- Giảm overhead: Không cần handshake mỗi request +- Better throughput: Multiple connections cho parallel requests + +**Ví dụ:** +```csharp +// Request 1: Tạo connection mới (~50ms) +var proxy1 = await _client.GetProxyAsync(); + +// Request 2-100: Reuse connection (~5ms mỗi request) +for (int i = 0; i < 100; i++) +{ + var proxy = await _client.GetProxyAsync(); +} +// Total time: ~50ms + (99 * 5ms) = ~545ms +// Without pooling: ~100 * 50ms = ~5000ms +``` + +### 5. Compression Mode + +**Cách hoạt động:** +- gRPC: Compression tự động với gzip/deflate +- HTTP: Accept-Encoding header +- Server compress response nếu client support + +**Cấu hình:** +```json +{ + "SmartPool": { + "EnableCompression": true, + "CompressionAlgorithm": "gzip" + } +} +``` + +**Lợi ích:** +- Giảm payload size ~30-50% +- Giảm bandwidth usage +- Faster transfer trên slow networks + +**Khi nào dùng:** +- ✅ Khi bandwidth là bottleneck +- ✅ Mobile networks +- ✅ High-latency networks +- ✅ Khi response size lớn + +**Trade-off:** +- CPU overhead cho compression/decompression +- Thường không đáng kể với modern CPUs + +## Best Practices + +### 1. Protocol Selection + +```csharp +// High-performance internal service → gRPC +services.AddSmartPoolClient(options => +{ + options.Protocol = SmartPoolProtocol.Grpc; +}); + +// External client → HTTP +services.AddSmartPoolClient(options => +{ + options.Protocol = SmartPoolProtocol.Http; +}); +``` + +### 2. Caching Strategy + +```csharp +// Random/Round-robin → Enable cache +services.AddSmartPoolClient(options => +{ + options.EnableClientCache = true; + options.ClientCacheDurationSeconds = 30; +}); + +// Least Delay/Adaptive Ranking → Disable cache +services.AddSmartPoolClient(options => +{ + options.EnableClientCache = false; // Cần real-time data +}); +``` + +### 3. Logging Strategy + +```csharp +// High-throughput → Fire-and-forget + Batch +services.AddSmartPoolClient(options => +{ + options.EnableFireAndForgetLogging = true; + options.EnableBatchLogging = true; + options.LogBatchSize = 50; +}); + +// Critical logging → Synchronous +services.AddSmartPoolClient(options => +{ + options.EnableFireAndForgetLogging = false; + options.EnableBatchLogging = false; +}); +``` + +### 4. Error Handling Pattern + +```csharp +// Detailed error handling +try +{ + var proxy = await _client.GetRawProxyAsync(request); +} +catch (NoAvailableProxiesException) +{ + // Retry với different token hoặc wait +} +catch (NoMatchingProxiesException) +{ + // Relax filters hoặc use different strategy +} +catch (SmartPoolException ex) +{ + _logger.LogError(ex, "SmartPool error: {ErrorCode}", ex.ErrorCode); +} + +// Silent failure +var proxy = await _client.TryGetRawProxyAsync(request); +if (proxy == null) +{ + // Fallback logic +} +``` + +### 5. Retry Pattern với Alternative Strategy + +```csharp +SmartProxyServer? currentProxy = null; +for (int retry = 0; retry < 3; retry++) +{ + try + { + var request = retry == 0 + ? new GetProxyRequest { strategy = "least_delay", target_domain = "facebook.com" } + : new GetProxyRequest + { + strategy = "alternative", + referer_proxy = currentProxy + }; + + currentProxy = await _client.GetRawProxyAsync(request); + + // Use proxy... + break; // Success + } + catch (NoMatchingProxiesException) + { + if (retry == 2) throw; // Last retry failed + // Continue to next retry + } +} +``` + +## Dependencies + +- .NET 10.0 +- MagicOnion.Client 6.1.7 +- Microsoft.Extensions.* 10.0.2 + +## Documentation + +- 📖 **[SDK Documentation](./SDK_DOCUMENTATION.md)** - Tài liệu chi tiết đầy đủ +- 📖 **[System README](../../SMARTPOOL_README.md)** - Tổng quan hệ thống + +## License + +Internal use only. diff --git a/docs/src/Icomm.SmartPool.Tests/README.md b/docs/src/Icomm.SmartPool.Tests/README.md new file mode 100644 index 0000000..ad7b57f --- /dev/null +++ b/docs/src/Icomm.SmartPool.Tests/README.md @@ -0,0 +1,43 @@ +# SmartPool Tests + +This project contains unit tests for the SmartPool system. + +## Test Structure + +- **Strategies/**: Tests for proxy selection strategies + - `RandomStrategyTests.cs`: Tests for random selection + - `AlternativeStrategyTests.cs`: Tests for alternative proxy selection + - `ProxyStrategyFactoryTests.cs`: Tests for strategy factory + +- **Client/**: Tests for SmartPool client SDK + - `SmartPoolClientTests.cs`: Tests for client initialization and configuration + +## Running Tests + +```bash +# Run all tests +dotnet test + +# Run with detailed output +dotnet test --logger "console;verbosity=detailed" + +# Run specific test class +dotnet test --filter "FullyQualifiedName~RandomStrategyTests" +``` + +## Test Coverage + +The tests cover: +- Strategy selection logic +- Fallback behaviors +- Filter application +- Client initialization +- Configuration validation + +## Adding New Tests + +When adding new strategies or features: +1. Create a new test class in the appropriate folder +2. Follow the existing naming convention: `{ClassName}Tests.cs` +3. Use FluentAssertions for readable assertions +4. Mock dependencies using Moq