# 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) > > 📌 **Migration note (quan trọng)**: [CLIENT_MIGRATION_NOTES.md](./CLIENT_MIGRATION_NOTES.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", "RequestTimeoutMs": 30000, "LogRequestTimeoutMs": 3000, "LogRetryMaxBatchSize": 50, "LogRetryFlushIntervalMs": 5000 } } ``` ### 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 request = new GetProxyRequest { access_token = "your-token", strategy = "least_delay", target_domain = "facebook.com", ip_version = "v6" }; var proxy = await _smartPoolClient.GetProxyAsync(request); if (proxy != null) { var handler = new HttpClientHandler { Proxy = proxy }; var httpClient = new HttpClient(handler); var response = await httpClient.GetAsync("https://facebook.com"); // Log usage var logRequest = new ProxyUsageLogRequest { access_token = "your-token", proxy_id = 123, // Get from GetRawProxyAsync if needed target_domain = "facebook.com", status_code = (int)response.StatusCode, response_time_ms = 450 }; await _smartPoolClient.LogProxyUsageAsync(logRequest); } } } ``` ## 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 (default) - **least_delay**: Fastest proxy (requires `target_domain`) - **adaptive_ranking**: Highest success rate (requires `target_domain`) - **alternative**: Similar proxy replacement (requires `referer_proxy.id`) ## 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.