一个具体的例子,用 ruby 写一个一个 自动生成 图片压缩的服务, 然后 转换成 go
require 'sinatra'
require 'open-uri'
require 'rmagick'
require 'time'
# Initialize cache
$image_cache = {}
# Cleanup task to remove stale cache entries
Thread.new do
loop do
sleep 8 * 60 * 60 # Sleep for 24 hours
current_time = Time.now
$image_cache.delete_if do |url, entry|
current_time - entry[:last_accessed] > 24 * 60 * 60
end
end
end
get '/' do
# Get the URL parameter
url = params['url']
# Ensure the URL is provided
halt 400, 'URL parameter is missing' if url.nil?
# Check cache for the image
if $image_cache.key?(url)
entry = $image_cache[url]
entry[:last_accessed] = Time.now
content_type 'image/jpeg'
return entry[:image_data]
end
# Fetch the image from the URL
begin
image_data = URI.open(url).read
rescue => e
halt 500, "Failed to fetch image: #{e.message}"
end
# Read the image data using RMagick
begin
image = Magick::Image.from_blob(image_data).first
rescue => e
halt 500, "Failed to read image: #{e.message}"
end
# Resize the image while maintaining the aspect ratio
begin
resized_image = image.change_geometry("360") do |cols, rows, img|
img.resize(cols, rows)
end
rescue => e
halt 500, "Failed to resize image: #{e.message}"
end
# Convert the resized image to a blob
resized_image_data = resized_image.to_blob
begin
# Convert the resized image to a blob
resized_image_data = resized_image.to_blob
rescue Magick::ImageMagickError => e
puts "Error: #{e.message}"
puts "Backtrace: #{e.backtrace.join("\n")}"
end
# Store the resized image in the cache
$image_cache[url] = {
image_data: resized_image_data,
last_accessed: Time.now
}
# Send the resized image data to the user
content_type 'image/jpeg'
resized_image_data
end%
转换后的代码,
package main
import (
"bytes"
"fmt"
"image"
"image/jpeg"
"log"
"net/http"
"sync"
"time"
"
github.com/nfnt/resize"
)
const (
port = 8300
cacheCleanupInterval = 8 * time.Hour
cacheExpirationTime = 24 * time.Hour
)
type CacheEntry struct {
ImageData []byte
LastAccessed time.Time
}
var (
imageCache = make(map[string]*CacheEntry)
cacheMutex sync.RWMutex
)
func main() {
go cleanupCache()
http.HandleFunc("/", handleRequest)
log.Printf("Server starting on port %d", port)
log.Fatal( http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}
func cleanupCache() {
for {
time.Sleep(cacheCleanupInterval)
currentTime := time.Now()
cacheMutex.Lock()
for url, entry := range imageCache {
if currentTime.Sub(entry.LastAccessed) > cacheExpirationTime {
delete(imageCache, url)
}
}
cacheMutex.Unlock()
}
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
url := r.URL.Query().Get("url")
if url == "" {
http.Error(w, "URL parameter is missing", http.StatusBadRequest)
return
}
cacheMutex.RLock()
if entry, ok := imageCache[url]; ok {
entry.LastAccessed = time.Now()
cacheMutex.RUnlock()
w.Header().Set("Content-Type", "image/jpeg")
w.Write(entry.ImageData)
return
}
cacheMutex.RUnlock()
log.Printf("Fetching image: %v\n", url)
resp, err := http.Get(url)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to fetch image: %v", err), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
img, _, err := image.Decode(resp.Body)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to decode image: %v", err), http.StatusInternalServerError)
return
}
resizedImg := resize.Resize(360, 0, img, resize.Lanczos3)
var buf bytes.Buffer
if err := jpeg.Encode(&buf, resizedImg, nil); err != nil {
http.Error(w, fmt.Sprintf("Failed to encode resized image: %v", err), http.StatusInternalServerError)
return
}
cacheMutex.Lock()
imageCache[url] = &CacheEntry{
ImageData: buf.Bytes(),
LastAccessed: time.Now(),
}
cacheMutex.Unlock()
w.Header().Set("Content-Type", "image/jpeg")
w.Write(buf.Bytes())
}%