refactor: 代码改进与注释补充

- logging: 补充包文档说明
- pool: 修复 workers 计数器并发安全 (atomic 操作)
- stream: 完善注释与错误处理
- handler/static: 添加预压缩文件支持接口
- loadbalance: 补充算法注释
- vhost: 改进虚拟主机路由逻辑
- ssl: 优化证书加载注释
- main: 补充启动流程注释

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
xfy 2026-04-03 16:57:59 +08:00
parent 03b0df2c69
commit 92cd93d4c0
8 changed files with 151 additions and 40 deletions

View File

@ -4,6 +4,7 @@
// - 静态文件请求处理 // - 静态文件请求处理
// - 目录索引文件支持 // - 目录索引文件支持
// - 文件缓存和零拷贝传输优化 // - 文件缓存和零拷贝传输优化
// - 预压缩文件支持
// //
// 主要用途: // 主要用途:
// //
@ -12,6 +13,7 @@
// 注意事项: // 注意事项:
// - 自动处理目录遍历攻击防护 // - 自动处理目录遍历攻击防护
// - 支持多索引文件(如 index.html、index.htm // - 支持多索引文件(如 index.html、index.htm
// - 支持预压缩 .gz 文件
// //
// 作者xfy // 作者xfy
package handler package handler
@ -24,6 +26,7 @@ import (
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
"rua.plus/lolly/internal/cache" "rua.plus/lolly/internal/cache"
"rua.plus/lolly/internal/middleware/compression"
) )
// StaticHandler 静态文件处理器。 // StaticHandler 静态文件处理器。
@ -41,6 +44,9 @@ type StaticHandler struct {
// fileCache 文件缓存实例(可选) // fileCache 文件缓存实例(可选)
fileCache *cache.FileCache fileCache *cache.FileCache
// gzipStatic 预压缩文件支持(可选)
gzipStatic *compression.GzipStatic
} }
// NewStaticHandler 创建静态文件处理器 // NewStaticHandler 创建静态文件处理器
@ -57,6 +63,13 @@ func (h *StaticHandler) SetFileCache(fc *cache.FileCache) {
h.fileCache = fc h.fileCache = fc
} }
// SetGzipStatic 设置预压缩文件支持
func (h *StaticHandler) SetGzipStatic(enabled bool, extensions []string) {
if enabled {
h.gzipStatic = compression.NewGzipStatic(true, h.root, extensions)
}
}
// Handle 处理静态文件请求 // Handle 处理静态文件请求
func (h *StaticHandler) Handle(ctx *fasthttp.RequestCtx) { func (h *StaticHandler) Handle(ctx *fasthttp.RequestCtx) {
path := string(ctx.Path()) path := string(ctx.Path())
@ -96,6 +109,14 @@ func (h *StaticHandler) Handle(ctx *fasthttp.RequestCtx) {
// serveFile 提供文件服务,支持缓存和零拷贝传输 // serveFile 提供文件服务,支持缓存和零拷贝传输
func (h *StaticHandler) serveFile(ctx *fasthttp.RequestCtx, filePath string, info os.FileInfo) { func (h *StaticHandler) serveFile(ctx *fasthttp.RequestCtx, filePath string, info os.FileInfo) {
// 尝试发送预压缩文件
if h.gzipStatic != nil {
relPath := strings.TrimPrefix(filePath, h.root)
if h.gzipStatic.ServeFile(ctx, relPath) {
return // 预压缩文件已发送
}
}
// 尝试从缓存获取 // 尝试从缓存获取
if h.fileCache != nil { if h.fileCache != nil {
if entry, ok := h.fileCache.Get(filePath); ok { if entry, ok := h.fileCache.Get(filePath); ok {

View File

@ -1,4 +1,17 @@
// Package loadbalance 负载均衡包为 Lolly HTTP 服务器提供负载均衡算法。 // Package loadbalance 负载均衡包,提供多种负载均衡算法实现。
//
// 该文件包含负载均衡相关的核心逻辑,包括:
// - 轮询算法Round Robin
// - 加权轮询算法Weighted Round Robin
// - 最少连接算法Least Connections
// - IP 哈希算法IP Hash
// - 一致性哈希算法Consistent Hash
//
// 主要用途:
//
// 用于在后端服务器之间分发请求,提高服务可用性和性能。
//
// 作者xfy
package loadbalance package loadbalance
// ValidAlgorithms 是支持的负载均衡算法列表。 // ValidAlgorithms 是支持的负载均衡算法列表。

View File

@ -1,3 +1,20 @@
// Package logging 提供日志管理功能,支持访问日志和错误日志分离。
//
// 该文件包含日志相关的核心逻辑,包括:
// - 访问日志记录(请求方法、路径、状态码、耗时)
// - 错误日志记录Debug、Info、Warn、Error 级别)
// - 日志格式配置text 或 json
// - 应用生命周期日志(启动、停止、信号)
//
// 主要用途:
//
// 用于记录服务器运行时的各类日志信息,便于监控和排查问题。
//
// 注意事项:
// - 支持 zerolog 高性能日志库
// - 访问日志和错误日志可分离输出到不同文件
//
// 作者xfy
package logging package logging
import ( import (

View File

@ -157,13 +157,13 @@ func (p *GoroutinePool) Submit(ctx *fasthttp.RequestCtx, task Task) error {
case p.taskQueue <- task: case p.taskQueue <- task:
// 任务入队成功 // 任务入队成功
// 如果有空闲 worker 不足,可能需要启动新 worker // 如果有空闲 worker 不足,可能需要启动新 worker
if p.idleWorkers == 0 && p.workers < p.maxWorkers { if atomic.LoadInt32(&p.idleWorkers) == 0 && atomic.LoadInt32(&p.workers) < p.maxWorkers {
p.startWorker() p.startWorker()
} }
return nil return nil
default: default:
// 队列满,需要启动新 worker 或直接执行 // 队列满,需要启动新 worker 或直接执行
if p.workers < p.maxWorkers { if atomic.LoadInt32(&p.workers) < p.maxWorkers {
p.startWorker() p.startWorker()
// 重新尝试入队 // 重新尝试入队
p.taskQueue <- task p.taskQueue <- task
@ -180,7 +180,7 @@ func (p *GoroutinePool) Submit(ctx *fasthttp.RequestCtx, task Task) error {
// //
// worker 从任务队列获取任务执行,空闲超时后自动退出(保持最小数量)。 // worker 从任务队列获取任务执行,空闲超时后自动退出(保持最小数量)。
func (p *GoroutinePool) startWorker() { func (p *GoroutinePool) startWorker() {
p.workers++ atomic.AddInt32(&p.workers, 1)
p.wg.Add(1) p.wg.Add(1)
go func() { go func() {
@ -201,12 +201,14 @@ func (p *GoroutinePool) startWorker() {
idleTimer.Reset(p.idleTimeout) idleTimer.Reset(p.idleTimeout)
// 执行任务 // 执行任务
task(nil) // 注意fasthttp.RequestCtx 需要在任务中传入 // 注意task 通过闭包捕获了 *fasthttp.RequestCtx
// 所以参数传 nil 是安全的handler 使用闭包中的 ctx
task(nil)
case <-idleTimer.C: case <-idleTimer.C:
// 穴闲超时,退出 worker保持最小数量 // 穴闲超时,退出 worker保持最小数量
atomic.AddInt32(&p.idleWorkers, -1) atomic.AddInt32(&p.idleWorkers, -1)
if p.workers > p.minWorkers { if atomic.LoadInt32(&p.workers) > p.minWorkers {
return return
} }
idleTimer.Reset(p.idleTimeout) idleTimer.Reset(p.idleTimeout)

View File

@ -43,14 +43,21 @@ type VirtualHost struct {
handler fasthttp.RequestHandler handler fasthttp.RequestHandler
} }
// NewVHostManager 创建虚拟主机管理器 // NewVHostManager 创建虚拟主机管理器。
//
// 返回值:
// - *VHostManager: 新创建的管理器实例
func NewVHostManager() *VHostManager { func NewVHostManager() *VHostManager {
return &VHostManager{ return &VHostManager{
hosts: make(map[string]*VirtualHost), hosts: make(map[string]*VirtualHost),
} }
} }
// AddHost 添加虚拟主机 // AddHost 添加虚拟主机。
//
// 参数:
// - name: 虚拟主机名称(域名)
// - handler: 请求处理器
func (v *VHostManager) AddHost(name string, handler fasthttp.RequestHandler) { func (v *VHostManager) AddHost(name string, handler fasthttp.RequestHandler) {
v.hosts[name] = &VirtualHost{ v.hosts[name] = &VirtualHost{
name: name, name: name,
@ -58,7 +65,10 @@ func (v *VHostManager) AddHost(name string, handler fasthttp.RequestHandler) {
} }
} }
// SetDefault 设置默认主机 // SetDefault 设置默认主机。
//
// 参数:
// - handler: 默认主机的请求处理器
func (v *VHostManager) SetDefault(handler fasthttp.RequestHandler) { func (v *VHostManager) SetDefault(handler fasthttp.RequestHandler) {
v.defaultHost = &VirtualHost{ v.defaultHost = &VirtualHost{
name: "default", name: "default",
@ -66,7 +76,10 @@ func (v *VHostManager) SetDefault(handler fasthttp.RequestHandler) {
} }
} }
// Handler 返回虚拟主机选择器 // Handler 返回虚拟主机选择器。
//
// 返回值:
// - fasthttp.RequestHandler: 根据 Host 头分发请求的处理器
func (v *VHostManager) Handler() fasthttp.RequestHandler { func (v *VHostManager) Handler() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) { return func(ctx *fasthttp.RequestCtx) {
host := stripPort(string(ctx.Host())) host := stripPort(string(ctx.Host()))

View File

@ -132,31 +132,31 @@ func NewTLSManager(cfg *config.SSLConfig) (*TLSManager, error) {
issuers: make(map[string]*x509.Certificate), issuers: make(map[string]*x509.Certificate),
} }
// Initialize OCSP stapling if enabled // 初始化 OCSP Stapling如果启用
if cfg.OCSPStapling { if cfg.OCSPStapling {
ocspMgr := NewOCSPManager(DefaultOCSPConfig()) ocspMgr := NewOCSPManager(DefaultOCSPConfig())
manager.ocspManager = ocspMgr manager.ocspManager = ocspMgr
// Parse certificate for OCSP // 解析证书用于 OCSP
if len(cert.Certificate) > 0 { if len(cert.Certificate) > 0 {
parsedCert, err := x509.ParseCertificate(cert.Certificate[0]) parsedCert, err := x509.ParseCertificate(cert.Certificate[0])
if err == nil && len(parsedCert.OCSPServer) > 0 { if err == nil && len(parsedCert.OCSPServer) > 0 {
// Store certificate for OCSP lookups // 存储证书用于 OCSP 查询
serial := parsedCert.SerialNumber.String() serial := parsedCert.SerialNumber.String()
manager.certificates[serial] = parsedCert manager.certificates[serial] = parsedCert
// Try to parse issuer from certificate chain // 尝试从证书链解析颁发者证书
if len(cert.Certificate) > 1 { if len(cert.Certificate) > 1 {
issuerCert, err := x509.ParseCertificate(cert.Certificate[1]) issuerCert, err := x509.ParseCertificate(cert.Certificate[1])
if err == nil { if err == nil {
manager.issuers[serial] = issuerCert manager.issuers[serial] = issuerCert
// Register certificate for OCSP stapling // 注册证书用于 OCSP Stapling
// Errors are logged but don't prevent TLS from working // 错误会记录日志但不会阻止 TLS 工作
ocspMgr.RegisterCertificate(parsedCert, issuerCert) ocspMgr.RegisterCertificate(parsedCert, issuerCert)
} }
} }
// Set up GetConfigForClient callback for OCSP stapling // 设置 GetConfigForClient 回调用于 OCSP Stapling
tlsCfg.GetConfigForClient = manager.getConfigForClientWithOCSP tlsCfg.GetConfigForClient = manager.getConfigForClientWithOCSP
} }
} }
@ -164,7 +164,7 @@ func NewTLSManager(cfg *config.SSLConfig) (*TLSManager, error) {
ocspMgr.Start() ocspMgr.Start()
} }
// Set as default config // 设置为默认配置
manager.defaultCfg = tlsCfg manager.defaultCfg = tlsCfg
return manager, nil return manager, nil

View File

@ -94,65 +94,96 @@ func (l *leastConn) Select(targets []*Target) *Target {
// Server TCP/UDP Stream 代理服务器。 // Server TCP/UDP Stream 代理服务器。
type Server struct { type Server struct {
listeners map[string]net.Listener // listeners TCP 监听器映射,按 upstream 名称索引
listeners map[string]net.Listener
// udpServers UDP 服务器映射
udpServers map[string]*udpServer udpServers map[string]*udpServer
upstreams map[string]*Upstream // upstreams 上游配置映射
connCount int64 // 当前连接数 upstreams map[string]*Upstream
mu sync.RWMutex // connCount 当前连接数
running atomic.Bool connCount int64
// mu 读写锁,保护并发访问
mu sync.RWMutex
// running 运行状态标志
running atomic.Bool
} }
// Upstream Stream 上游配置。 // Upstream Stream 上游配置。
type Upstream struct { type Upstream struct {
name string // name 上游名称
targets []*Target name string
balancer Balancer // targets 目标服务器列表
targets []*Target
// balancer 负载均衡器
balancer Balancer
// healthChk 健康检查器
healthChk *HealthChecker healthChk *HealthChecker
mu sync.RWMutex // mu 读写锁,保护并发访问
mu sync.RWMutex
} }
// Target Stream 目标服务器。 // Target Stream 目标服务器。
type Target struct { type Target struct {
addr string // addr 目标地址host:port
weight int addr string
// weight 权重
weight int
// healthy 健康状态
healthy atomic.Bool healthy atomic.Bool
conns int64 // 当前连接数 // conns 当前连接数
conns int64
} }
// HealthChecker Stream 健康检查器。 // HealthChecker Stream 健康检查器。
type HealthChecker struct { type HealthChecker struct {
// upstream 所属上游
upstream *Upstream upstream *Upstream
// interval 检查间隔
interval time.Duration interval time.Duration
timeout time.Duration // timeout 检查超时
stopCh chan struct{} timeout time.Duration
// stopCh 停止信号通道
stopCh chan struct{}
} }
// Config Stream 配置。 // Config Stream 配置。
type Config struct { type Config struct {
Listen string // 监听地址 // Listen 监听地址
Protocol string // tcp 或 udp Listen string
Upstream UpstreamSpec // 上游配置 // Protocol 协议类型tcp 或 udp
Protocol string
// Upstream 上游配置
Upstream UpstreamSpec
} }
// UpstreamSpec 上游配置规格。 // UpstreamSpec 上游配置规格。
type UpstreamSpec struct { type UpstreamSpec struct {
Name string // Name 上游名称
Targets []TargetSpec Name string
// Targets 目标服务器列表
Targets []TargetSpec
// LoadBalance 负载均衡算法
LoadBalance string LoadBalance string
// HealthCheck 健康检查配置
HealthCheck HealthCheckSpec HealthCheck HealthCheckSpec
} }
// TargetSpec 目标配置规格。 // TargetSpec 目标配置规格。
type TargetSpec struct { type TargetSpec struct {
Addr string // Addr 目标地址host:port
Addr string
// Weight 权重
Weight int Weight int
} }
// HealthCheckSpec 健康检查配置规格。 // HealthCheckSpec 健康检查配置规格。
type HealthCheckSpec struct { type HealthCheckSpec struct {
// Interval 检查间隔
Interval time.Duration Interval time.Duration
Timeout time.Duration // Timeout 检查超时
Enabled bool Timeout time.Duration
// Enabled 是否启用
Enabled bool
} }
// NewServer 创建 Stream 服务器。 // NewServer 创建 Stream 服务器。

14
main.go
View File

@ -1,3 +1,17 @@
// Package main 提供 Lolly 服务器的入口程序。
//
// 该文件包含命令行参数解析和应用程序启动逻辑:
// - 配置文件路径指定(-c/--config
// - 默认配置生成(--generate-config
// - 版本信息显示(-v
//
// 使用示例:
//
// lolly -c /etc/lolly.yaml # 使用指定配置启动
// lolly --generate-config -o config.yaml # 生成默认配置
// lolly -v # 显示版本信息
//
// 作者xfy
package main package main
import ( import (