import { Hono } from 'hono'
import { cron } from 'hono/cron'
import mysql from 'mysql2/promise'

// 创建 MySQL 连接池
const pool = mysql.createPool({
  host: process.env.DB_HOST || 'localhost',
  user: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || 'password',
  database: process.env.DB_NAME || 'cdn_weights',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
})

const app = new Hono()

// 缓存域名列表和权重
let domainsCache = []

// 刷新缓存函数
async function refreshDomains() {
  try {
    const [rows] = await pool.query(
      'SELECT domain, weight FROM domains WHERE active = 1 ORDER BY id ASC'
    )
    domainsCache = rows
    console.log('Domains cache updated:', domainsCache)
  } catch (error) {
    console.error('Error refreshing domains:', error)
  }
}

// 加权选择算法
function selectWeightedDomain(domains) {
  if (domains.length === 0) return null
  
  // 计算总权重
  const totalWeight = domains.reduce((sum, domain) => sum + domain.weight, 0)
  let random = Math.random() * totalWeight
  
  // 寻找匹配的域名
  let current = 0
  for (const domain of domains) {
    current += domain.weight
    if (random <= current) {
      return domain
    }
  }
  
  // 兜底返回最后一个
  return domains[domains.length - 1]
}

// 每小时刷新一次缓存
cron('0 */1 * * *', async () => {
  await refreshDomains()
})

// 初始化时立即刷新缓存
refreshDomains().catch(console.error)

// 图片请求处理
app.get('/image/*', async (c) => {
  const domains = domainsCache
  
  if (domains.length === 0) {
    return c.text('No available CDN domains', 503)
  }
  
  const selectedDomain = selectWeightedDomain(domains)
  const imagePath = c.req.path
  
  // 构建 CDN URL
  const cdnUrl = `https://${selectedDomain.domain}${imagePath}`
  
  // 可以选择直接重定向或代理请求
  return c.redirect(cdnUrl, 302)
})

// 管理接口:更新域名权重
app.post('/admin/domain/:domain', async (c) => {
  const domain = c.req.param('domain')
  const { weight } = await c.req.json()
  
  try {
    await pool.query(
      'UPDATE domains SET weight = ? WHERE domain = ?',
      [weight, domain]
    )
    await refreshDomains() // 立即刷新缓存
    return c.json({ success: true, message: 'Domain updated' })
  } catch (error) {
    console.error('Update domain error:', error)
    return c.json({ success: false, message: 'Update failed' }, 500)
  }
})

// 启动服务器
const port = process.env.PORT || 3000
console.log(`Server running on port ${port}`)
export default {
  port,
  fetch: app.fetch
}

‌MySQL 表结构‌:

CREATE TABLE domains (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  domain VARCHAR(255) NOT NULL UNIQUE,
  weight INT NOT NULL DEFAULT 1,
  active TINYINT(1) NOT NULL DEFAULT 1,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

‌环境变量 (.env)‌:

text
Copy Code
DB_HOST=localhost
DB_USER=your_user
DB_PASSWORD=your_password
DB_NAME=cdn_weights
PORT=3000

‌功能说明‌:

‌加权轮询算法‌:通过概率分布实现权重分配,保证高权重域名被更频繁选中 ‌缓存机制‌:定时刷新域名数据,减少数据库压力 ‌健康检查‌:通过 active 字段控制域名可用性 ‌管理接口‌:提供实时更新域名权重的 API ‌自动重定向‌:根据权重选择最优 CDN 域名进行重定向 ‌使用示例‌:

添加测试数据:

sql
Copy Code
INSERT INTO domains (domain, weight) VALUES
('cdn1.example.com', 3),
('cdn2.example.com', 2),
('cdn3.example.com', 1);
更新域名权重:
bash
Copy Code
curl -X POST -H "Content-Type: application/json" -d '{"weight":5}' http://localhost:3000/admin/domain/cdn1.example.com

‌优化建议‌:

添加域名健康检查机制,自动更新 active 状态 实现 JWT 认证保护管理接口 增加请求日志记录和分析 添加速率限制防止滥用 实现平滑权重调整算法(如动态权重调整) 这个方案通过组合 MySQL 的持久化存储和 Hono 的高性能路由处理,实现了灵活可配置的加权 CDN 分发系统。管理员可以通过数据库直接管理 CDN 节点权重,系统会自动根据配置的权重值进行流量分配。 image.png.webp