diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..a7a6682 --- /dev/null +++ b/.env.example @@ -0,0 +1,10 @@ +# Discourse SSO 配置 +# Discourse 网站地址 +DISCOURSE_URL=https://discourse.example.com + +# SSO 密钥 (必需) +# 可以使用以下命令生成: openssl rand -hex 32 +DISCOURSE_SSO_SECRET=your_sso_secret_here + +# 服务器配置 +PORT=8000 \ No newline at end of file diff --git a/.gitignore b/.gitignore index f7d95e9..e83a6d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,31 @@ kaifa.md + +# 环境变量配置 +.env +.env.local +.env.*.local + +# 系统文件 +.DS_Store +Thumbs.db + +# IDE 配置 +.idea/ +.vscode/ +*.sublime-project +*.sublime-workspace + +# 依赖目录 +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# 构建输出 +dist/ +build/ +out/ + +# 日志文件 +*.log +logs/ diff --git a/main.ts b/main.ts index 11e6d3c..5b059b6 100644 --- a/main.ts +++ b/main.ts @@ -1,12 +1,125 @@ import { serve } from "https://deno.land/std@0.220.1/http/server.ts"; +import { createHmac } from "crypto"; + +// 类型定义 +interface Vendor { + id: number; + name: string; + icon: string; +} + +interface VendorResponse { + data: { + [key: string]: Vendor; + }; +} -// 在文件开头添加接口定义 interface Price { + id?: string; model: string; - type: string; + billing_type: 'tokens' | 'times'; channel_type: number; - input: number; - output: number; + currency: 'CNY' | 'USD'; + input_price: number; + output_price: number; + input_ratio: number; + output_ratio: number; + price_source: string; + status: 'pending' | 'approved' | 'rejected'; + created_by: string; + created_at: string; + reviewed_by?: string; + reviewed_at?: string; +} + +// 缓存供应商数据 +let vendorsCache: VendorResponse | null = null; +let vendorsCacheTime: number = 0; +const CACHE_DURATION = 1000 * 60 * 5; // 5分钟缓存 + +// 获取供应商数据 +async function getVendors(): Promise { + const now = Date.now(); + if (vendorsCache && (now - vendorsCacheTime) < CACHE_DURATION) { + return vendorsCache; + } + + try { + const response = await fetch('https://oapi.czl.net/api/ownedby'); + const data = await response.json() as VendorResponse; + vendorsCache = data; + vendorsCacheTime = now; + return data; + } catch (error) { + console.error('获取供应商数据失败:', error); + throw new Error('获取供应商数据失败'); + } +} + +// 计算倍率 +function calculateRatio(price: number, currency: 'CNY' | 'USD'): number { + return currency === 'USD' ? price / 2 : price / 14; +} + +// 验证价格数据 +function validatePrice(data: any): string | null { + if (!data.model || !data.billing_type || !data.channel_type || + !data.currency || data.input_price === undefined || data.output_price === undefined || + !data.price_source) { + return "所有字段都是必需的"; + } + + if (data.billing_type !== 'tokens' && data.billing_type !== 'times') { + return "计费类型必须是 tokens 或 times"; + } + + if (data.currency !== 'CNY' && data.currency !== 'USD') { + return "币种必须是 CNY 或 USD"; + } + + if (isNaN(data.input_price) || isNaN(data.output_price)) { + return "价格必须是数字"; + } + + if (data.input_price < 0 || data.output_price < 0) { + return "价格不能为负数"; + } + + return null; +} + +// 添加 Discourse SSO 配置 +const DISCOURSE_URL = Deno.env.get('DISCOURSE_URL') || 'https://discourse.czl.net'; +const DISCOURSE_SSO_SECRET = Deno.env.get('DISCOURSE_SSO_SECRET'); + +// 验证必需的环境变量 +if (!DISCOURSE_SSO_SECRET) { + console.error('错误: 必须设置 DISCOURSE_SSO_SECRET 环境变量'); + Deno.exit(1); +} + +// 添加认证相关函数 +async function verifyDiscourseSSO(request: Request): Promise { + const cookie = request.headers.get('cookie'); + if (!cookie) return null; + + const sessionMatch = cookie.match(/session=([^;]+)/); + if (!sessionMatch) return null; + + const sessionId = sessionMatch[1]; + const session = await kv.get(['sessions', sessionId]); + + if (!session.value) return null; + return session.value.username; +} + +// 添加登录和登出函数 +function generateSSO(returnUrl: string): string { + const payload = Buffer.from(`return_sso_url=${encodeURIComponent(returnUrl)}`).toString('base64'); + const sig = createHmac('sha256', DISCOURSE_SSO_SECRET) + .update(payload) + .digest('hex'); + return `${DISCOURSE_URL}/session/sso_provider?sso=${encodeURIComponent(payload)}&sig=${sig}`; } // HTML 页面 @@ -14,105 +127,415 @@ const html = ` AI Models Price API + + +
-

AI Models Price API

- -