/**
* API 大锅饭插件 - 标准插件格式
*
* 功能:
* 1. API Key 管理(创建、删除、启用/禁用)
* 2. 每日配额限制
* 3. 用量统计
* 4. 管理 API 接口
*/
import {
createKey,
listKeys,
getKey,
deleteKey,
updateKeyLimit,
resetKeyUsage,
toggleKey,
updateKeyName,
validateKey,
incrementUsage,
getStats,
KEY_PREFIX,
setConfigGetter
} from './key-manager.js';
import {
extractPotluckKey,
isPotluckRequest,
sendPotluckError
} from './middleware.js';
import { consumeBonus, getConfig } from './user-data-manager.js';
import { handlePotluckApiRoutes, handlePotluckUserApiRoutes, startHealthCheckScheduler, stopHealthCheckScheduler } from './api-routes.js';
/**
* 插件定义
*/
const apiPotluckPlugin = {
name: 'api-potluck',
version: '1.0.1',
description: 'API 大锅饭 - Key 管理和用量统计插件
管理端:potluck.html
用户端:potluck-user.html',
// 插件类型:认证插件
type: 'auth',
// 优先级:数字越小越先执行,默认认证插件优先级为 9999
_priority: 10,
/**
* 初始化钩子
* @param {Object} config - 服务器配置
*/
async init(config) {
console.log('[API Potluck Plugin] Initializing...');
// 注入配置获取函数
setConfigGetter(getConfig);
// 启动定时健康检查
startHealthCheckScheduler();
},
/**
* 销毁钩子
*/
async destroy() {
console.log('[API Potluck Plugin] Destroying...');
// 停止定时健康检查
stopHealthCheckScheduler();
},
/**
* 静态文件路径
*/
staticPaths: ['potluck.html', 'potluck-user.html'],
/**
* 路由定义
*/
routes: [
{
method: '*',
path: '/api/potluckuser',
handler: handlePotluckUserApiRoutes
},
{
method: '*',
path: '/api/potluck',
handler: handlePotluckApiRoutes
}
],
/**
* 认证方法 - 处理 Potluck Key 认证
* @param {http.IncomingMessage} req - HTTP 请求
* @param {http.ServerResponse} res - HTTP 响应
* @param {URL} requestUrl - 解析后的 URL
* @param {Object} config - 服务器配置
* @returns {Promise<{handled: boolean, authorized: boolean|null, error?: Object, data?: Object}>}
*/
async authenticate(req, res, requestUrl, config) {
const apiKey = extractPotluckKey(req, requestUrl);
if (!apiKey) {
// 不是 potluck 请求,返回 null 让其他认证插件处理
return { handled: false, authorized: null };
}
// 验证 Key
const validation = await validateKey(apiKey);
if (!validation.valid) {
const errorMessages = {
'invalid_format': 'Invalid API key format',
'not_found': 'API key not found',
'disabled': 'API key has been disabled',
'quota_exceeded': 'Quota exceeded for this API key'
};
const statusCodes = {
'invalid_format': 401,
'not_found': 401,
'disabled': 403,
'quota_exceeded': 429
};
const error = {
statusCode: statusCodes[validation.reason] || 401,
message: errorMessages[validation.reason] || 'Authentication failed',
code: validation.reason,
keyData: validation.keyData
};
// 发送错误响应
sendPotluckError(res, error);
return { handled: true, authorized: false, error };
}
// 认证成功,返回数据供后续使用
console.log(`[API Potluck Plugin] Authorized with key: ${apiKey.substring(0, 12)}...`);
return {
handled: false,
authorized: true,
data: {
potluckApiKey: apiKey,
potluckKeyData: validation.keyData
}
};
},
/**
* 钩子函数
*/
hooks: {
/**
* 内容生成后钩子 - 记录用量
* @param {Object} config - 服务器配置
*/
async onContentGenerated(config) {
if (config.potluckApiKey) {
try {
// 传入资源包消耗回调
await incrementUsage(config.potluckApiKey, async (apiKey) => {
await consumeBonus(apiKey);
});
} catch (e) {
// 静默失败,不影响主流程
console.error('[API Potluck Plugin] Failed to record usage:', e.message);
}
}
}
},
// 导出内部函数供外部使用(可选)
exports: {
createKey,
listKeys,
getKey,
deleteKey,
updateKeyLimit,
resetKeyUsage,
toggleKey,
updateKeyName,
validateKey,
incrementUsage,
getStats,
KEY_PREFIX,
getConfig,
extractPotluckKey,
isPotluckRequest
}
};
export default apiPotluckPlugin;
// 也导出命名导出,方便直接引用
export {
createKey,
listKeys,
getKey,
deleteKey,
updateKeyLimit,
resetKeyUsage,
toggleKey,
updateKeyName,
validateKey,
incrementUsage,
getStats,
KEY_PREFIX,
getConfig,
extractPotluckKey,
isPotluckRequest
};