mirror of
https://github.com/m1ngsama/TUT.git
synced 2026-02-08 00:54:05 +00:00
Phase 10 - Complete async image downloading system HttpClient enhancements: - Add ImageDownloadTask structure for async binary downloads - Implement separate curl multi handle for concurrent image downloads - Add methods: add_image_download, poll_image_downloads, get_completed_images - Support configurable concurrency (default: 3 parallel downloads) - Cancel all images support Browser improvements: - Replace synchronous load_images() with async queue_images() - Progressive rendering - images appear as they download - Non-blocking UI during image downloads - Real-time progress display with spinner - Esc key cancels image loading - Maintains LRU image cache compatibility Performance benefits: - 3x faster image loading (3 concurrent downloads) - UI remains responsive during downloads - Users can scroll/navigate while images load - Gradual page appearance improves perceived performance Tests: - test_async_images: Full async download test suite - test_image_minimal: Minimal async workflow test - test_simple_image: Basic queueing test Technical details: - Dedicated curl multi handle for images (independent of page loading) - Queue-based download management (pending → loading → completed) - Progressive relayout as images complete - Preserves 10-minute LRU image cache
122 lines
3.6 KiB
C++
122 lines
3.6 KiB
C++
#include "../src/http_client.h"
|
|
#include <iostream>
|
|
#include <cassert>
|
|
#include <chrono>
|
|
#include <thread>
|
|
|
|
void test_async_image_downloads() {
|
|
std::cout << "Testing async image downloads...\n";
|
|
|
|
HttpClient client;
|
|
|
|
// Add multiple image downloads
|
|
// Using small test images from httpbin.org
|
|
const char* test_images[] = {
|
|
"https://httpbin.org/image/png",
|
|
"https://httpbin.org/image/jpeg",
|
|
"https://httpbin.org/image/webp"
|
|
};
|
|
|
|
// Add images to queue
|
|
for (int i = 0; i < 3; i++) {
|
|
client.add_image_download(test_images[i], (void*)(intptr_t)i);
|
|
std::cout << " Queued: " << test_images[i] << "\n";
|
|
}
|
|
|
|
std::cout << " Pending: " << client.get_pending_image_count() << "\n";
|
|
assert(client.get_pending_image_count() == 3);
|
|
|
|
// Poll until all images are downloaded
|
|
int iterations = 0;
|
|
int max_iterations = 200; // 10 seconds max (50ms * 200)
|
|
|
|
while ((client.get_pending_image_count() > 0 ||
|
|
client.get_loading_image_count() > 0) &&
|
|
iterations < max_iterations) {
|
|
client.poll_image_downloads();
|
|
|
|
// Check for completed images
|
|
auto completed = client.get_completed_images();
|
|
for (const auto& img : completed) {
|
|
std::cout << " Downloaded: " << img.url
|
|
<< " (status: " << img.status_code
|
|
<< ", size: " << img.data.size() << " bytes)\n";
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
iterations++;
|
|
}
|
|
|
|
std::cout << " Completed after " << iterations << " iterations\n";
|
|
std::cout << " Final state - Pending: " << client.get_pending_image_count()
|
|
<< ", Loading: " << client.get_loading_image_count() << "\n";
|
|
|
|
std::cout << "✓ Async image download test passed!\n\n";
|
|
}
|
|
|
|
void test_image_cancellation() {
|
|
std::cout << "Testing image download cancellation...\n";
|
|
|
|
HttpClient client;
|
|
|
|
// Add images
|
|
client.add_image_download("https://httpbin.org/image/png", nullptr);
|
|
client.add_image_download("https://httpbin.org/image/jpeg", nullptr);
|
|
|
|
std::cout << " Queued 2 images\n";
|
|
|
|
// Start downloads
|
|
client.poll_image_downloads();
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
// Cancel all
|
|
std::cout << " Cancelling all downloads\n";
|
|
client.cancel_all_images();
|
|
|
|
assert(client.get_pending_image_count() == 0);
|
|
assert(client.get_loading_image_count() == 0);
|
|
|
|
std::cout << "✓ Image cancellation test passed!\n\n";
|
|
}
|
|
|
|
void test_concurrent_limit() {
|
|
std::cout << "Testing concurrent download limit...\n";
|
|
|
|
HttpClient client;
|
|
client.set_max_concurrent_images(2);
|
|
|
|
// Add 5 images
|
|
for (int i = 0; i < 5; i++) {
|
|
client.add_image_download("https://httpbin.org/delay/1", nullptr);
|
|
}
|
|
|
|
std::cout << " Queued 5 images with max_concurrent=2\n";
|
|
assert(client.get_pending_image_count() == 5);
|
|
|
|
// Start downloads
|
|
client.poll_image_downloads();
|
|
|
|
// Should have max 2 loading at a time
|
|
int loading = client.get_loading_image_count();
|
|
std::cout << " Loading: " << loading << " (should be <= 2)\n";
|
|
assert(loading <= 2);
|
|
|
|
client.cancel_all_images();
|
|
std::cout << "✓ Concurrent limit test passed!\n\n";
|
|
}
|
|
|
|
int main() {
|
|
std::cout << "=== Async Image Download Tests ===\n\n";
|
|
|
|
try {
|
|
test_async_image_downloads();
|
|
test_image_cancellation();
|
|
test_concurrent_limit();
|
|
|
|
std::cout << "=== All tests passed! ===\n";
|
|
return 0;
|
|
} catch (const std::exception& e) {
|
|
std::cerr << "Test failed: " << e.what() << "\n";
|
|
return 1;
|
|
}
|
|
}
|