mirror of
https://github.com/woodchen-ink/webp_server_go.git
synced 2025-07-18 05:32:02 +08:00
143 lines
4.0 KiB
Go
143 lines
4.0 KiB
Go
package handler
|
||
|
||
import (
|
||
"net/http"
|
||
"net/url"
|
||
"path"
|
||
"strconv"
|
||
"strings"
|
||
"webp_server_go/config"
|
||
"webp_server_go/encoder"
|
||
"webp_server_go/helper"
|
||
|
||
"github.com/gofiber/fiber/v2"
|
||
log "github.com/sirupsen/logrus"
|
||
)
|
||
|
||
func Convert(c *fiber.Ctx) error {
|
||
// 检查是否为根路径
|
||
if c.Path() == "/" {
|
||
return c.SendString("Welcome to CZL WebP Server")
|
||
}
|
||
|
||
var (
|
||
reqHostname = c.Hostname()
|
||
reqHeader = &c.Request().Header
|
||
|
||
reqURIRaw, _ = url.QueryUnescape(c.Path())
|
||
reqURIwithQueryRaw, _ = url.QueryUnescape(c.OriginalURL())
|
||
reqURI = path.Clean(reqURIRaw)
|
||
reqURIwithQuery = path.Clean(reqURIwithQueryRaw)
|
||
|
||
filename = path.Base(reqURI)
|
||
realRemoteAddr = ""
|
||
targetHostName = ""
|
||
targetHost = ""
|
||
|
||
width, _ = strconv.Atoi(c.Query("width"))
|
||
height, _ = strconv.Atoi(c.Query("height"))
|
||
maxHeight, _ = strconv.Atoi(c.Query("max_height"))
|
||
maxWidth, _ = strconv.Atoi(c.Query("max_width"))
|
||
extraParams = config.ExtraParams{
|
||
Width: width,
|
||
Height: height,
|
||
MaxWidth: maxWidth,
|
||
MaxHeight: maxHeight,
|
||
}
|
||
)
|
||
|
||
log.Debugf("Incoming connection from %s %s %s", c.IP(), reqHostname, reqURIwithQuery)
|
||
|
||
// 检查路径是否匹配 IMG_MAP 中的任何前缀
|
||
var matchedPrefix string
|
||
var matchedTarget string
|
||
for prefix, target := range config.Config.ImageMap {
|
||
if strings.HasPrefix(reqURI, prefix) {
|
||
matchedPrefix = prefix
|
||
matchedTarget = target
|
||
break
|
||
}
|
||
}
|
||
|
||
// 如果不匹配任何 IMG_MAP 前缀,直接返回 404
|
||
if matchedPrefix == "" {
|
||
log.Warnf("请求的路径不匹配任何配置的 IMG_MAP: %s", c.Path())
|
||
return c.SendStatus(fiber.StatusNotFound)
|
||
}
|
||
|
||
// 设置目标主机信息
|
||
targetUrl, _ := url.Parse(matchedTarget)
|
||
targetHostName = targetUrl.Host
|
||
targetHost = targetUrl.Scheme + "://" + targetUrl.Host
|
||
|
||
// 调整请求 URI
|
||
reqURI = strings.Replace(reqURI, matchedPrefix, targetUrl.Path, 1)
|
||
reqURIwithQuery = strings.Replace(reqURIwithQuery, matchedPrefix, targetUrl.Path, 1)
|
||
|
||
// 构造远程地址
|
||
realRemoteAddr = targetHost + reqURIwithQuery
|
||
|
||
// 处理非图片文件
|
||
if !helper.IsImageFile(filename) {
|
||
log.Infof("Non-image file requested: %s", reqURI)
|
||
log.Infof("Redirecting to: %s", realRemoteAddr)
|
||
return c.Redirect(realRemoteAddr, fiber.StatusFound)
|
||
}
|
||
|
||
// 检查允许的文件类型
|
||
if !helper.CheckAllowedType(filename) {
|
||
msg := "不允许的文件扩展名 " + filename
|
||
log.Warn(msg)
|
||
return c.Status(http.StatusBadRequest).SendString(msg)
|
||
}
|
||
|
||
// 获取远程图像元数据
|
||
metadata := fetchRemoteImg(realRemoteAddr, targetHostName)
|
||
rawImageAbs := path.Join(config.Config.RemoteRawPath, targetHostName, metadata.Id)
|
||
|
||
// 后续的图像处理逻辑
|
||
supportedFormats := helper.GuessSupportedFormat(reqHeader)
|
||
|
||
// 检查原始图像是否存在
|
||
if !helper.ImageExists(rawImageAbs) {
|
||
helper.DeleteMetadata(reqURIwithQuery, targetHostName)
|
||
msg := "Image not found!"
|
||
log.Warn(msg)
|
||
return c.Status(404).SendString(msg)
|
||
}
|
||
|
||
// 检查文件大小
|
||
isSmall, err := helper.IsFileSizeSmall(rawImageAbs, 100*1024) // 100KB
|
||
if err != nil {
|
||
log.Errorf("检查文件大小时出错: %v", err)
|
||
return c.SendStatus(fiber.StatusInternalServerError)
|
||
}
|
||
|
||
if isSmall {
|
||
log.Infof("文件 %s 小于100KB,跳过转换", rawImageAbs)
|
||
return c.SendFile(rawImageAbs)
|
||
}
|
||
|
||
avifAbs, webpAbs, jxlAbs := helper.GenOptimizedAbsPath(metadata, targetHostName)
|
||
// 根据支持的格式和配置进行转换
|
||
encoder.ConvertFilter(rawImageAbs, jxlAbs, avifAbs, webpAbs, extraParams, supportedFormats, nil)
|
||
|
||
var availableFiles = []string{rawImageAbs}
|
||
if supportedFormats["avif"] {
|
||
availableFiles = append(availableFiles, avifAbs)
|
||
}
|
||
if supportedFormats["webp"] {
|
||
availableFiles = append(availableFiles, webpAbs)
|
||
}
|
||
if supportedFormats["jxl"] {
|
||
availableFiles = append(availableFiles, jxlAbs)
|
||
}
|
||
|
||
finalFilename := helper.FindSmallestFiles(availableFiles)
|
||
contentType := helper.GetFileContentType(finalFilename)
|
||
c.Set("Content-Type", contentType)
|
||
|
||
c.Set("X-Compression-Rate", helper.GetCompressionRate(rawImageAbs, finalFilename))
|
||
return c.SendFile(finalFilename)
|
||
}
|