Files
freezelib/examples/07-batch/main.go
2025-07-18 19:02:23 +08:00

681 lines
15 KiB
Go

package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"github.com/landaiqing/freezelib"
)
func main() {
fmt.Println("📦 Batch Processing Examples")
fmt.Println("=============================")
// Create output directory
os.MkdirAll("output", 0755)
os.MkdirAll("sample_files", 0755)
// Run batch examples
createSampleFiles()
batchFileProcessingExample()
multiFormatBatchExample()
concurrentProcessingExample()
directoryProcessingExample()
fmt.Println("\n✅ Batch processing examples completed!")
fmt.Println("📁 Check the 'output' directory for generated files.")
}
// Create sample files for batch processing
func createSampleFiles() {
fmt.Println("\n📝 Creating Sample Files")
fmt.Println("------------------------")
sampleFiles := map[string]string{
"sample_files/main.go": `package main
import (
"fmt"
"net/http"
"log"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
})
fmt.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}`,
"sample_files/utils.py": `import json
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime
logger = logging.getLogger(__name__)
def load_config(config_path: str) -> Dict[str, Any]:
"""Load configuration from JSON file."""
try:
with open(config_path, 'r') as f:
return json.load(f)
except FileNotFoundError:
logger.error(f"Config file not found: {config_path}")
return {}
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON in config file: {e}")
return {}
def format_timestamp(timestamp: Optional[datetime] = None) -> str:
"""Format timestamp to ISO string."""
if timestamp is None:
timestamp = datetime.now()
return timestamp.isoformat()
class DataProcessor:
def __init__(self, config: Dict[str, Any]):
self.config = config
self.processed_count = 0
def process_batch(self, items: List[Any]) -> List[Any]:
"""Process a batch of items."""
results = []
for item in items:
processed = self.process_item(item)
if processed:
results.append(processed)
self.processed_count += 1
return results
def process_item(self, item: Any) -> Optional[Any]:
"""Process a single item."""
# Implementation depends on item type
return item`,
"sample_files/api.js": `const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP'
});
app.use('/api/', limiter);
// Routes
app.get('/api/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
app.get('/api/users', async (req, res) => {
try {
const { page = 1, limit = 10 } = req.query;
const users = await getUsersPaginated(page, limit);
res.json({
data: users,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total: await getTotalUsers()
}
});
} catch (error) {
console.error('Error fetching users:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(PORT, () => {
console.log('Server running on port \${PORT}\');
});`,
"sample_files/styles.css": `/* Modern CSS Reset and Base Styles */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--primary-color: #3b82f6;
--secondary-color: #64748b;
--success-color: #10b981;
--warning-color: #f59e0b;
--error-color: #ef4444;
--background-color: #ffffff;
--surface-color: #f8fafc;
--text-primary: #1e293b;
--text-secondary: #64748b;
--border-color: #e2e8f0;
--shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: var(--text-primary);
background-color: var(--background-color);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
.card {
background: var(--surface-color);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 1.5rem;
box-shadow: var(--shadow);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 6px;
font-weight: 500;
text-decoration: none;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-primary {
background-color: var(--primary-color);
color: white;
}
.btn-primary:hover {
background-color: #2563eb;
transform: translateY(-1px);
}`,
"sample_files/config.json": `{
"database": {
"host": "localhost",
"port": 5432,
"name": "myapp",
"user": "postgres",
"password": "password",
"ssl": false,
"pool": {
"min": 2,
"max": 10,
"idle_timeout": "30s"
}
},
"redis": {
"host": "localhost",
"port": 6379,
"password": "",
"db": 0,
"pool_size": 10
},
"server": {
"host": "0.0.0.0",
"port": 8080,
"read_timeout": "30s",
"write_timeout": "30s",
"idle_timeout": "60s"
},
"logging": {
"level": "info",
"format": "json",
"output": "stdout"
},
"features": {
"enable_metrics": true,
"enable_tracing": true,
"enable_profiling": false
}
}`,
}
for filename, content := range sampleFiles {
err := os.WriteFile(filename, []byte(content), 0644)
if err != nil {
fmt.Printf("❌ Error creating %s: %v\n", filename, err)
continue
}
fmt.Printf("✅ Created: %s\n", filename)
}
}
// Batch file processing example
func batchFileProcessingExample() {
fmt.Println("\n📦 Batch File Processing")
fmt.Println("------------------------")
// Get all sample files
files, err := filepath.Glob("sample_files/*")
if err != nil {
fmt.Printf("❌ Error finding files: %v\n", err)
return
}
// Create a consistent freeze instance for all files
freeze := freezelib.New().
WithTheme("github-dark").
WithFont("JetBrains Mono", 14).
WithWindow(true).
WithLineNumbers(true).
WithShadow(15, 0, 8).
WithPadding(20)
fmt.Printf("🔄 Processing %d files...\n", len(files))
successCount := 0
for _, file := range files {
fmt.Printf("📄 Processing: %s\n", file)
// Detect language from file extension
ext := filepath.Ext(file)
lang := detectLanguage(ext)
svgData, err := freeze.GenerateFromFile(file)
if err != nil {
fmt.Printf("❌ Error processing %s: %v\n", file, err)
continue
}
// Create output filename
baseName := strings.TrimSuffix(filepath.Base(file), ext)
outputFile := fmt.Sprintf("output/batch_%s.svg", baseName)
err = os.WriteFile(outputFile, svgData, 0644)
if err != nil {
fmt.Printf("❌ Error saving %s: %v\n", outputFile, err)
continue
}
fmt.Printf("✅ Generated: %s (language: %s)\n", outputFile, lang)
successCount++
}
fmt.Printf("📊 Batch processing completed: %d/%d files successful\n",
successCount, len(files))
}
// Multi-format batch example
func multiFormatBatchExample() {
fmt.Println("\n🎨 Multi-format Batch Processing")
fmt.Println("--------------------------------")
code := `#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
template<typename T>
class SmartVector {
private:
std::unique_ptr<T[]> data;
size_t size_;
size_t capacity_;
public:
SmartVector(size_t initial_capacity = 10)
: data(std::make_unique<T[]>(initial_capacity))
, size_(0)
, capacity_(initial_capacity) {}
void push_back(const T& value) {
if (size_ >= capacity_) {
resize();
}
data[size_++] = value;
}
T& operator[](size_t index) {
if (index >= size_) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
size_t size() const { return size_; }
void sort() {
std::sort(data.get(), data.get() + size_);
}
private:
void resize() {
capacity_ *= 2;
auto new_data = std::make_unique<T[]>(capacity_);
std::copy(data.get(), data.get() + size_, new_data.get());
data = std::move(new_data);
}
};
int main() {
SmartVector<int> vec;
for (int i = 0; i < 15; ++i) {
vec.push_back(rand() % 100);
}
vec.sort();
std::cout << "Sorted vector: ";
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << vec[i] << " ";
}
std::cout << std::endl;
return 0;
}`
// Different format configurations
formats := []struct {
name string
format string
theme string
}{
{"svg_light", "svg", "github"},
{"svg_dark", "svg", "github-dark"},
{"png_presentation", "png", "dracula"},
{"png_print", "png", "github"},
}
freeze := freezelib.New().
WithFont("Cascadia Code", 14).
WithWindow(true).
WithLineNumbers(true).
WithShadow(15, 0, 8).
WithPadding(25)
for _, format := range formats {
fmt.Printf("🎨 Generating %s format...\n", format.name)
freeze.WithTheme(format.theme)
var data []byte
var err error
var filename string
if format.format == "svg" {
data, err = freeze.GenerateFromCode(code, "cpp")
filename = fmt.Sprintf("output/multiformat_%s.svg", format.name)
} else {
data, err = freeze.GeneratePNGFromCode(code, "cpp")
filename = fmt.Sprintf("output/multiformat_%s.png", format.name)
}
if err != nil {
fmt.Printf("❌ Error: %v\n", err)
continue
}
err = os.WriteFile(filename, data, 0644)
if err != nil {
fmt.Printf("❌ Error saving: %v\n", err)
continue
}
// Show file size
info, _ := os.Stat(filename)
fmt.Printf("✅ Generated: %s (%d bytes)\n", filename, info.Size())
}
}
// Concurrent processing example
func concurrentProcessingExample() {
fmt.Println("\n⚡ Concurrent Processing")
fmt.Println("-----------------------")
// Sample code snippets for concurrent processing
codeSnippets := []struct {
name string
code string
lang string
}{
{
"snippet1",
`def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print([fibonacci(i) for i in range(10)])`,
"python",
},
{
"snippet2",
`function quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[Math.floor(arr.length / 2)];
const left = arr.filter(x => x < pivot);
const middle = arr.filter(x => x === pivot);
const right = arr.filter(x => x > pivot);
return [...quickSort(left), ...middle, ...quickSort(right)];
}`,
"javascript",
},
{
"snippet3",
`public class BinarySearch {
public static int search(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
}`,
"java",
},
{
"snippet4",
`use std::collections::HashMap;
fn word_count(text: &str) -> HashMap<String, usize> {
text.split_whitespace()
.map(|word| word.to_lowercase())
.fold(HashMap::new(), |mut acc, word| {
*acc.entry(word).or_insert(0) += 1;
acc
})
}`,
"rust",
},
}
// Create freeze instance
freeze := freezelib.New().
WithTheme("nord").
WithFont("JetBrains Mono", 13).
WithWindow(true).
WithLineNumbers(true).
WithShadow(10, 0, 5).
WithPadding(20)
// Use goroutines for concurrent processing
var wg sync.WaitGroup
results := make(chan string, len(codeSnippets))
fmt.Printf("🚀 Processing %d snippets concurrently...\n", len(codeSnippets))
for _, snippet := range codeSnippets {
wg.Add(1)
go func(s struct {
name string
code string
lang string
}) {
defer wg.Done()
svgData, err := freeze.GenerateFromCode(s.code, s.lang)
if err != nil {
results <- fmt.Sprintf("❌ Error processing %s: %v", s.name, err)
return
}
filename := fmt.Sprintf("output/concurrent_%s.svg", s.name)
err = os.WriteFile(filename, svgData, 0644)
if err != nil {
results <- fmt.Sprintf("❌ Error saving %s: %v", filename, err)
return
}
results <- fmt.Sprintf("✅ Generated: %s", filename)
}(snippet)
}
// Wait for all goroutines to complete
go func() {
wg.Wait()
close(results)
}()
// Collect results
for result := range results {
fmt.Println(result)
}
}
// Directory processing example
func directoryProcessingExample() {
fmt.Println("\n📁 Directory Processing")
fmt.Println("-----------------------")
// Process all files in sample_files directory
err := filepath.Walk("sample_files", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Skip directories
if info.IsDir() {
return nil
}
// Only process certain file types
ext := filepath.Ext(path)
if !isSupportedFile(ext) {
return nil
}
fmt.Printf("📄 Processing directory file: %s\n", path)
// Create themed freeze instance based on file type
theme := getThemeForFile(ext)
freeze := freezelib.New().
WithTheme(theme).
WithFont("SF Mono", 13).
WithWindow(true).
WithLineNumbers(true).
WithPadding(20)
svgData, err := freeze.GenerateFromFile(path)
if err != nil {
fmt.Printf("❌ Error processing %s: %v\n", path, err)
return nil
}
// Create output filename
baseName := strings.TrimSuffix(filepath.Base(path), ext)
outputFile := fmt.Sprintf("output/directory_%s.svg", baseName)
err = os.WriteFile(outputFile, svgData, 0644)
if err != nil {
fmt.Printf("❌ Error saving %s: %v\n", outputFile, err)
return nil
}
fmt.Printf("✅ Generated: %s (theme: %s)\n", outputFile, theme)
return nil
})
if err != nil {
fmt.Printf("❌ Error walking directory: %v\n", err)
}
}
// Helper functions
func detectLanguage(ext string) string {
switch ext {
case ".go":
return "go"
case ".py":
return "python"
case ".js":
return "javascript"
case ".css":
return "css"
case ".json":
return "json"
default:
return "text"
}
}
func isSupportedFile(ext string) bool {
supported := []string{".go", ".py", ".js", ".css", ".json", ".md", ".txt"}
for _, s := range supported {
if ext == s {
return true
}
}
return false
}
func getThemeForFile(ext string) string {
switch ext {
case ".go":
return "github-dark"
case ".py":
return "monokai"
case ".js":
return "dracula"
case ".css":
return "github"
case ".json":
return "nord"
default:
return "github"
}
}