|
|
@@ -1,12 +1,43 @@
|
|
|
-import { Hono } from 'hono'
|
|
|
-import type { Variables , WithAuth } from './middlewares.ts'
|
|
|
+import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
|
|
|
+import { ErrorSchema } from '@/server/utils/errorHandler';
|
|
|
+import { AuthContext } from '@/server/types/context';
|
|
|
+import { authMiddleware } from '@/server/middleware/auth.middleware';
|
|
|
+import * as process from 'node:process'
|
|
|
|
|
|
// 配置信息
|
|
|
-const IM_APP_ID = Deno.env.get('IM_APP_ID');
|
|
|
-const IM_APP_KEY = Deno.env.get('IM_APP_KEY');
|
|
|
-const IM_APP_SIGN = Deno.env.get('IM_APP_SIGN');
|
|
|
-const RTC_APP_ID = Deno.env.get('RTC_APP_ID')
|
|
|
-const RTC_APP_KEY = Deno.env.get('RTC_APP_KEY')
|
|
|
+const IM_APP_ID = process.env.IM_APP_ID || '';
|
|
|
+const IM_APP_KEY = process.env.IM_APP_KEY || '';
|
|
|
+const IM_APP_SIGN = process.env.IM_APP_SIGN || '';
|
|
|
+const RTC_APP_ID = process.env.RTC_APP_ID || '';
|
|
|
+const RTC_APP_KEY = process.env.RTC_APP_KEY || '';
|
|
|
+// 请求和响应Schema定义
|
|
|
+const CreateImTokenRequest = z.object({
|
|
|
+ role: z.string().openapi({
|
|
|
+ description: '用户角色',
|
|
|
+ example: 'teacher'
|
|
|
+ })
|
|
|
+});
|
|
|
+
|
|
|
+const ImTokenResponse = z.object({
|
|
|
+ nonce: z.string().openapi({ description: '随机字符串' }),
|
|
|
+ token: z.string().openapi({ description: 'IM认证令牌' }),
|
|
|
+ timestamp: z.number().openapi({ description: '时间戳' }),
|
|
|
+ appId: z.string().openapi({ description: '应用ID' }),
|
|
|
+ appSign: z.string().openapi({ description: '应用签名' })
|
|
|
+});
|
|
|
+
|
|
|
+const CreateRtcTokenRequest = z.object({
|
|
|
+ channelId: z.string().openapi({
|
|
|
+ description: '频道ID',
|
|
|
+ example: 'classroom_123'
|
|
|
+ })
|
|
|
+});
|
|
|
+
|
|
|
+const RtcTokenResponse = z.object({
|
|
|
+ token: z.string().openapi({ description: 'RTC认证令牌' }),
|
|
|
+ timestamp: z.number().openapi({ description: '时间戳' }),
|
|
|
+ appId: z.string().openapi({ description: '应用ID' })
|
|
|
+});
|
|
|
|
|
|
const hex = (buffer: ArrayBuffer): string => {
|
|
|
const hexCodes = [];
|
|
|
@@ -58,62 +89,117 @@ const generateImToken = async (userId: string, role: string): Promise<{
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-export function createClassRoomRoutes(withAuth: WithAuth) {
|
|
|
- const tokenRoutes = new Hono<{ Variables: Variables }>()
|
|
|
+// 创建IM Token路由
|
|
|
+const createImTokenRoute = createRoute({
|
|
|
+ method: 'post',
|
|
|
+ path: '/im_token',
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ request: {
|
|
|
+ body: {
|
|
|
+ content: {
|
|
|
+ 'application/json': { schema: CreateImTokenRequest }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '成功生成IM Token',
|
|
|
+ content: { 'application/json': { schema: ImTokenResponse } }
|
|
|
+ },
|
|
|
+ 401: {
|
|
|
+ description: '未授权',
|
|
|
+ content: { 'application/json': { schema: ErrorSchema } }
|
|
|
+ },
|
|
|
+ 500: {
|
|
|
+ description: '服务器错误',
|
|
|
+ content: { 'application/json': { schema: ErrorSchema } }
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
|
|
|
- // 生成IM Token
|
|
|
- tokenRoutes.post('/im_token', withAuth, async (c) => {
|
|
|
+// 创建RTC Token路由
|
|
|
+const createRtcTokenRoute = createRoute({
|
|
|
+ method: 'post',
|
|
|
+ path: '/rtc_token',
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ request: {
|
|
|
+ body: {
|
|
|
+ content: {
|
|
|
+ 'application/json': { schema: CreateRtcTokenRequest }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '成功生成RTC Token',
|
|
|
+ content: { 'application/json': { schema: RtcTokenResponse } }
|
|
|
+ },
|
|
|
+ 401: {
|
|
|
+ description: '未授权',
|
|
|
+ content: { 'application/json': { schema: ErrorSchema } }
|
|
|
+ },
|
|
|
+ 500: {
|
|
|
+ description: '服务器错误',
|
|
|
+ content: { 'application/json': { schema: ErrorSchema } }
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 创建API应用实例
|
|
|
+const app = new OpenAPIHono<AuthContext>()
|
|
|
+ .openapi(createImTokenRoute, async (c) => {
|
|
|
try {
|
|
|
- const { role } = await c.req.json()
|
|
|
- const user = c.get('user')
|
|
|
+ const { role } = c.req.valid('json');
|
|
|
+ const user = c.get('user');
|
|
|
+
|
|
|
if (!user || typeof user !== 'object' || !('id' in user)) {
|
|
|
- return c.json({ error: '用户信息无效' }, 401)
|
|
|
+ return c.json({ code: 401, message: '用户信息无效' }, 401);
|
|
|
}
|
|
|
-
|
|
|
|
|
|
- // 生成Token
|
|
|
- const { nonce, token , timestamp } = await generateImToken(user.id.toString(), role);
|
|
|
+ const { nonce, token, timestamp } = await generateImToken(user.id.toString(), role);
|
|
|
|
|
|
return c.json({
|
|
|
- nonce,
|
|
|
+ nonce,
|
|
|
token,
|
|
|
timestamp,
|
|
|
appId: IM_APP_ID,
|
|
|
appSign: IM_APP_SIGN,
|
|
|
- })
|
|
|
+ }, 200);
|
|
|
} catch (error) {
|
|
|
- console.error('生成IM Token失败:', error)
|
|
|
- return c.json({ error: '生成IM Token失败' }, 500)
|
|
|
+ console.error('生成IM Token失败:', error);
|
|
|
+ return c.json({
|
|
|
+ code: 500,
|
|
|
+ message: error instanceof Error ? error.message : '生成IM Token失败'
|
|
|
+ }, 500);
|
|
|
}
|
|
|
})
|
|
|
-
|
|
|
- // 生成RTC Token
|
|
|
- tokenRoutes.post('/rtc_token', withAuth, async (c) => {
|
|
|
+ .openapi(createRtcTokenRoute, async (c) => {
|
|
|
try {
|
|
|
- const { channelId } = await c.req.json()
|
|
|
- const user = c.get('user')
|
|
|
-
|
|
|
+ const { channelId } = c.req.valid('json');
|
|
|
+ const user = c.get('user');
|
|
|
+
|
|
|
if (!user || typeof user !== 'object' || !('id' in user)) {
|
|
|
- return c.json({ error: '用户信息无效' }, 401)
|
|
|
+ return c.json({ code: 401, message: '用户信息无效' }, 401);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (!RTC_APP_ID || !RTC_APP_KEY) {
|
|
|
- return c.json({ error: '服务配置不完整' }, 500)
|
|
|
+ return c.json({ code: 500, message: '服务配置不完整' }, 500);
|
|
|
}
|
|
|
|
|
|
- // 生成Token
|
|
|
- const { token , timestamp } = await generateRTCToken(channelId, user.id.toString());
|
|
|
+ const { token, timestamp } = await generateRTCToken(channelId, user.id.toString());
|
|
|
|
|
|
return c.json({
|
|
|
token,
|
|
|
timestamp,
|
|
|
appId: RTC_APP_ID,
|
|
|
- })
|
|
|
+ }, 200);
|
|
|
} catch (error) {
|
|
|
- console.error('生成RTC Token失败:', error)
|
|
|
- return c.json({ error: '生成RTC Token失败' }, 500)
|
|
|
+ console.error('生成RTC Token失败:', error);
|
|
|
+ return c.json({
|
|
|
+ code: 500,
|
|
|
+ message: error instanceof Error ? error.message : '生成RTC Token失败'
|
|
|
+ }, 500);
|
|
|
}
|
|
|
- })
|
|
|
+ });
|
|
|
|
|
|
- return tokenRoutes
|
|
|
-}
|
|
|
+export default app;
|