diff --git a/app.config.json5 b/app.config.json5 index 872a19f..6badf60 100644 --- a/app.config.json5 +++ b/app.config.json5 @@ -8,5 +8,6 @@ domain: 'kevisual.xiongxiao.me', resources: 'https://minio.xiongxiao.me/resources', allowedOrigins: ['localhost', 'xiongxiao.me', 'zxj.im', 'silkyai.cn'], + home: '/ai/chat', }, } diff --git a/package.json b/package.json index 8663de5..e676b5b 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ "@kevisual/use-config": "^1.0.8", "archiver": "^7.0.1", "ioredis": "^5.5.0", - "nanoid": "^5.1.2" + "nanoid": "^5.1.2", + "sequelize": "^6.37.5" }, "resolutions": { "picomatch": "^4.0.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2bd2066..dcd4456 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: nanoid: specifier: ^5.1.2 version: 5.1.2 + sequelize: + specifier: ^6.37.5 + version: 6.37.5(pg@8.13.3) devDependencies: '@rollup/plugin-commonjs': specifier: ^28.0.2 diff --git a/rollup.config.js b/rollup.config.js index eb5f12a..e156975 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -25,5 +25,5 @@ export default { declaration: false, }), // 使用 @rollup/plugin-typescript 处理 TypeScript 文件 ], - external: ['ioredis', '@kevisual/router', '@kevisual/use-config'], + external: ['ioredis', '@kevisual/router', '@kevisual/use-config', 'sequelize'], }; diff --git a/src/app.ts b/src/app.ts index 96d2648..cb7755e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,5 @@ import { App } from '@kevisual/router'; - +// import { redis } from './module/redis/redis.ts'; export const app = new App({ serverOptions: { path: '/api/proxy', diff --git a/src/module/config.ts b/src/module/config.ts index c3ddddf..3eea30d 100644 --- a/src/module/config.ts +++ b/src/module/config.ts @@ -27,6 +27,11 @@ type ConfigType = { * 允许跨域访问的地址 */ allowOrigin: string[]; + + /** + * home 不在代理范围内跳转到的地址 + */ + home: string; }; }; diff --git a/src/module/index.ts b/src/module/index.ts index 42787eb..855b098 100644 --- a/src/module/index.ts +++ b/src/module/index.ts @@ -10,12 +10,13 @@ import { createRefreshHtml } from './html/create-refresh-html.ts'; const api = config?.api || { host: 'kevisual.xiongxiao.me', path: '/api/router' }; const domain = config?.proxy?.domain || 'kevisual.xiongxiao.me'; const allowedOrigins = config?.proxy?.allowOrigin || []; +const home = config?.proxy?.home || '/ai/chat'; const noProxyUrl = ['/', '/favicon.ico']; export const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => { if (req.url === '/favicon.ico') { res.writeHead(200, { 'Content-Type': 'image/x-icon' }); - res.write('proxy no favicon.ico\n'); + res.end('proxy no favicon.ico\n'); return; } if (req.url.startsWith('/api/proxy')) { @@ -97,13 +98,13 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR const data = await UserApp.getDomainApp(dns.hostName); if (!data) { res.writeHead(404, { 'Content-Type': 'text/plain' }); - res.write('Invalid domain\n'); - return res.end(); + res.end('Invalid domain\n'); + return; } if (!data.user || !data.app) { res.writeHead(404, { 'Content-Type': 'text/plain' }); - res.write('Invalid domain config\n'); - return res.end(); + res.end('Invalid domain config\n'); + return; } user = data.user; app = data.app; @@ -113,6 +114,13 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR const pathname = new URL(req.url, `http://${dns.hostName}`).pathname; const url = pathname; if (!domainApp && noProxyUrl.includes(url)) { + if (url === '/') { + // 获取一下登陆用户,如果没有登陆用户,重定向到ai-chat页面 + // 重定向到 + res.writeHead(302, { Location: home }); + return res.end(); + } + // 不是域名代理,且是在不代理的url当中 res.write('No proxy for this URL\n'); return res.end(); } diff --git a/src/module/models.ts b/src/module/models.ts new file mode 100644 index 0000000..a193ff3 --- /dev/null +++ b/src/module/models.ts @@ -0,0 +1,5 @@ +import { User, UserInit, Org, OrgInit } from '@kevisual/code-center-module'; + +export { User, Org }; +UserInit(); +OrgInit(); diff --git a/src/module/redis/redis.ts b/src/module/redis/redis.ts index 6fec661..b46e24b 100644 --- a/src/module/redis/redis.ts +++ b/src/module/redis/redis.ts @@ -1,23 +1,27 @@ import { Redis } from 'ioredis'; import { useConfig } from '@kevisual/use-config'; +import { useContextKey } from '@kevisual/use-config/context'; const config = useConfig<{ redis: ConstructorParameters; }>(); +const init = () => { + return new Redis({ + host: 'localhost', // Redis 服务器的主机名或 IP 地址 + port: 6379, // Redis 服务器的端口号 + // password: 'your_password', // Redis 的密码 (如果有) + db: 0, // 要使用的 Redis 数据库索引 (0-15) + keyPrefix: '', // key 前缀 + retryStrategy(times) { + // 连接重试策略 + return Math.min(times * 50, 2000); // 每次重试时延迟增加 + }, + maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试) + ...config.redis, + }); +}; // 配置 Redis 连接 -export const redis = new Redis({ - host: 'localhost', // Redis 服务器的主机名或 IP 地址 - port: 6379, // Redis 服务器的端口号 - // password: 'your_password', // Redis 的密码 (如果有) - db: 0, // 要使用的 Redis 数据库索引 (0-15) - keyPrefix: '', // key 前缀 - retryStrategy(times) { - // 连接重试策略 - return Math.min(times * 50, 2000); // 每次重试时延迟增加 - }, - maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试) - ...config.redis, -}); +export const redis = useContextKey('redis', init); export const subscriber = redis.duplicate(); // 创建一个订阅者连接 async function ensureKeyspaceNotifications() { diff --git a/src/module/sequelize.ts b/src/module/sequelize.ts new file mode 100644 index 0000000..97c3a99 --- /dev/null +++ b/src/module/sequelize.ts @@ -0,0 +1,30 @@ +import { useConfig } from '@kevisual/use-config'; +import { Sequelize } from 'sequelize'; +import { useContextKey, useContext } from '@kevisual/use-config/context'; + +type PostgresConfig = { + postgres: { + username: string; + password: string; + host: string; + port: number; + database: string; + }; +}; +const config = useConfig(); + +const postgresConfig = config.postgres; + +if (!postgresConfig) { + console.error('postgres config is required'); + process.exit(1); +} +// connect to db +export const init = () => { + return new Sequelize({ + dialect: 'postgres', + ...postgresConfig, + // logging: false, + }); +}; +export const sequelize = useContextKey('sequelize', init); diff --git a/src/route/app/list.ts b/src/route/app/list.ts index af4f359..6c5e9f6 100644 --- a/src/route/app/list.ts +++ b/src/route/app/list.ts @@ -4,10 +4,24 @@ import { redis } from '@/module/redis/redis.ts'; import fs from 'fs'; import { fileStore } from '../../module/config.ts'; +app + .route({ + path: 'app', + key: 'auth-admin', + }) + .define(async (ctx) => { + const { user } = ctx.query; + if (user !== 'admin') { + ctx.throw('Not Found'); + } + }) + .addTo(app); + app .route({ path: 'app', key: 'list', + middleware: ['auth-admin'], }) .define(async (ctx) => { const keys = await redis.keys('user:app:*'); @@ -24,6 +38,7 @@ app .route({ path: 'app', key: 'delete', + middleware: ['auth-admin'], }) .define(async (ctx) => { const { user, app } = ctx.query; @@ -76,6 +91,7 @@ app .route({ path: 'app', key: 'get', + middleware: ['auth-admin'], }) .define(async (ctx) => { const { user, app } = ctx.query; @@ -100,6 +116,7 @@ app .route({ path: 'app', key: 'status', + middleware: ['auth-admin'], }) .define(async (ctx) => { const { user, app } = ctx.query;