diff --git a/src/modules/html/studio-app-list/index.ts b/src/modules/html/studio-app-list/index.ts new file mode 100644 index 0000000..364ea31 --- /dev/null +++ b/src/modules/html/studio-app-list/index.ts @@ -0,0 +1,344 @@ +type StudioOpts = { user: string, userAppKey?: string; appIds: string[] } +export const createStudioAppListHtml = (opts: StudioOpts) => { + const user = opts.user!; + const userAppKey = opts?.userAppKey; + let showUserAppKey = userAppKey; + if (showUserAppKey && showUserAppKey.startsWith(user + '-')) { + showUserAppKey = showUserAppKey.replace(user + '-', ''); + } + const pathApps = opts?.appIds?.map(appId => { + const shortAppId = appId.replace(opts!.user + '-', '') + return { + appId, + shortAppId, + pathname: `/${user}/v1/${shortAppId}` + }; + }) || [] + + // 应用列表内容 + const appListContent = ` +
+

Studio 应用列表

+

用户: ${user}

+
+ +
+ ${pathApps.map((app, index) => ` + +
+
+

${app.shortAppId}

+

${app.pathname}

+
+
+
+ `).join('')} +
+ + ${pathApps.length === 0 ? ` +
+
📭
+

暂无应用

+
+ ` : ''} + ` + + return ` + + + + + + Studio - ${user} 的应用 + + + +
+ ${showUserAppKey ? ` +
+ +

应用不存在

+

抱歉,您访问的应用 ${showUserAppKey || ''} 不存在。

+

请检查应用 Key 是否正确,或联系管理员。

+ ← 返回应用列表 +
+ ` : ''} + ${appListContent} + + +
+ + + `; +}; diff --git a/src/modules/ws-proxy/manager.ts b/src/modules/ws-proxy/manager.ts index 04514d8..2abec23 100644 --- a/src/modules/ws-proxy/manager.ts +++ b/src/modules/ws-proxy/manager.ts @@ -71,7 +71,10 @@ export class WsProxyManager { } this.wssMap.delete(id); } - getIds() { + getIds(beginWith?: string) { + if (beginWith) { + return Array.from(this.wssMap.keys()).filter(key => key.startsWith(beginWith)); + } return Array.from(this.wssMap.keys()); } get(id: string) { diff --git a/src/modules/ws-proxy/proxy.ts b/src/modules/ws-proxy/proxy.ts index 1deda4d..6486118 100644 --- a/src/modules/ws-proxy/proxy.ts +++ b/src/modules/ws-proxy/proxy.ts @@ -4,6 +4,7 @@ import { wsProxyManager } from './index.ts'; import { App } from '@kevisual/router'; import { logger } from '../logger.ts'; import { getLoginUser } from '@/modules/auth.ts'; +import { createStudioAppListHtml } from '../html/studio-app-list/index.ts'; type ProxyOptions = { createNotFoundPage: (msg?: string) => any; @@ -13,13 +14,10 @@ export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opt const _url = new URL(url || '', `http://localhost`); const { pathname, searchParams } = _url; let [user, app, userAppKey] = pathname.split('/').slice(1); - if (!user || !app || !userAppKey) { + if (!user || !app) { opts?.createNotFoundPage?.('应用未找到'); return false; } - if (!userAppKey.includes('-')) { - userAppKey = user + '-' + userAppKey; - } const data = await App.handleRequest(req, res); const loginUser = await getLoginUser(req); @@ -27,7 +25,26 @@ export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opt opts?.createNotFoundPage?.('没有登录'); return false; } + const isAdmin = loginUser.tokenUser?.username === user + + if (!userAppKey) { + if (isAdmin) { + // 获取所有的管理员的应用列表 + const ids = wsProxyManager.getIds(user + '-'); + const html = createStudioAppListHtml({ user, appIds: ids, userAppKey }); + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(html); + return; + } else { + opts?.createNotFoundPage?.('没有访问应用权限'); + return false; + } + } + if (!userAppKey.includes('-')) { + userAppKey = user + '-' + userAppKey; + } + // TODO: 如果不是管理员,是否需要添加其他人可以访问的逻辑? if (!isAdmin) { opts?.createNotFoundPage?.('没有访问应用权限'); @@ -38,10 +55,12 @@ export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opt } logger.debug('data', data); const client = wsProxyManager.get(userAppKey); - const ids = wsProxyManager.getIds(); + const ids = wsProxyManager.getIds(user + '-'); if (!client) { if (isAdmin) { - opts?.createNotFoundPage?.(`未找到应用 [${userAppKey}], 当前应用列表: ${ids.join(',')}`); + const html = createStudioAppListHtml({ user, appIds: ids, userAppKey }); + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(html); } else { opts?.createNotFoundPage?.('应用访问失败'); }