feat: add permission for link data, and default public
This commit is contained in:
		@@ -8,6 +8,8 @@ import { pipeline } from 'stream';
 | 
			
		||||
import { promisify } from 'util';
 | 
			
		||||
import { fetchApp, fetchDomain, fetchTest } from './query/get-router.ts';
 | 
			
		||||
import { getAppLoadStatus, setAppLoadStatus, AppLoadStatus } from './redis/get-app-status.ts';
 | 
			
		||||
import { bucketName, minioClient, minioResources } from './minio.ts';
 | 
			
		||||
import { downloadFileFromMinio } from './proxy/http-proxy.ts';
 | 
			
		||||
 | 
			
		||||
const pipelineAsync = promisify(pipeline);
 | 
			
		||||
 | 
			
		||||
@@ -391,13 +393,18 @@ export const deleteUserAppFiles = async (user: string, app: string) => {
 | 
			
		||||
  }
 | 
			
		||||
  // console.log('deleteUserAppFiles', res);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
async function downloadFile(fileUrl: string, destFile: string) {
 | 
			
		||||
  if (fileUrl.startsWith(minioResources)) {
 | 
			
		||||
    await downloadFileFromMinio(fileUrl, destFile);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  console.log('destFile', destFile, 'fileUrl', fileUrl);
 | 
			
		||||
  const res = await fetch(fileUrl);
 | 
			
		||||
 | 
			
		||||
  if (!res.ok) {
 | 
			
		||||
    throw new Error(`Failed to fetch ${fileUrl}: ${res.statusText}`);
 | 
			
		||||
  }
 | 
			
		||||
  console.log('destFile', destFile);
 | 
			
		||||
  const destStream = fs.createWriteStream(destFile);
 | 
			
		||||
 | 
			
		||||
  // 使用 `pipeline` 将 `res.body` 中的数据传递给 `destStream`
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import { getContentType } from './get-content-type.ts';
 | 
			
		||||
import { createRefreshHtml } from './html/create-refresh-html.ts';
 | 
			
		||||
import { fileProxy } from './proxy/file-proxy.ts';
 | 
			
		||||
import net from 'net';
 | 
			
		||||
import { httpProxy } from './proxy/http-proxy.ts';
 | 
			
		||||
 | 
			
		||||
const api = config?.api || { host: 'kevisual.xiongxiao.me', path: '/api/router' };
 | 
			
		||||
const domain = config?.proxy?.domain || 'kevisual.xiongxiao.me';
 | 
			
		||||
@@ -125,7 +126,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
 | 
			
		||||
  const url = pathname;
 | 
			
		||||
  if (!domainApp && noProxyUrl.includes(url)) {
 | 
			
		||||
    if (url === '/') {
 | 
			
		||||
      // 获取一下登陆用户,如果没有登陆用户,重定向到ai-chat页面
 | 
			
		||||
      // TODO: 获取一下登陆用户,如果没有登陆用户,重定向到ai-chat页面
 | 
			
		||||
      // 重定向到
 | 
			
		||||
      res.writeHead(302, { Location: home });
 | 
			
		||||
      return res.end();
 | 
			
		||||
@@ -168,7 +169,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
 | 
			
		||||
    res.write('Server Error\n');
 | 
			
		||||
    res.end();
 | 
			
		||||
  };
 | 
			
		||||
  const createNotFoundPage = (msg?: string) => {
 | 
			
		||||
  const createNotFoundPage = async (msg?: string) => {
 | 
			
		||||
    res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
 | 
			
		||||
    res.write(msg || 'Not Found App\n');
 | 
			
		||||
    res.end();
 | 
			
		||||
@@ -208,27 +209,11 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
 | 
			
		||||
        return createNotFoundPage('Invalid proxy url');
 | 
			
		||||
      }
 | 
			
		||||
      console.log('proxyUrl', appFileUrl, proxyUrl);
 | 
			
		||||
      let protocol = proxyUrl.startsWith('https') ? https : http;
 | 
			
		||||
      // 代理
 | 
			
		||||
      const proxyReq = protocol.request(proxyUrl, (proxyRes) => {
 | 
			
		||||
        res.writeHead(proxyRes.statusCode, {
 | 
			
		||||
          ...proxyRes.headers,
 | 
			
		||||
        });
 | 
			
		||||
        if (proxyRes.statusCode === 404) {
 | 
			
		||||
          userApp.clearCacheData();
 | 
			
		||||
          return createNotFoundPage('Invalid proxy url');
 | 
			
		||||
        }
 | 
			
		||||
        if (proxyRes.statusCode === 302) {
 | 
			
		||||
          res.writeHead(302, { Location: proxyRes.headers.location });
 | 
			
		||||
          return res.end();
 | 
			
		||||
        }
 | 
			
		||||
        proxyRes.pipe(res, { end: true });
 | 
			
		||||
      httpProxy(req, res, {
 | 
			
		||||
        proxyUrl,
 | 
			
		||||
        userApp,
 | 
			
		||||
        createNotFoundPage,
 | 
			
		||||
      });
 | 
			
		||||
      proxyReq.on('error', (err) => {
 | 
			
		||||
        console.error(`Proxy request error: ${err.message}`);
 | 
			
		||||
        userApp.clearCacheData();
 | 
			
		||||
      });
 | 
			
		||||
      proxyReq.end();
 | 
			
		||||
      // userApp.clearCacheData()
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,10 @@ type MinioConfig = {
 | 
			
		||||
  minio: ClientOptions & { bucketName: string };
 | 
			
		||||
};
 | 
			
		||||
const config = useConfig<MinioConfig>();
 | 
			
		||||
 | 
			
		||||
const { bucketName, ...minioRest } = config.minio;
 | 
			
		||||
const { port, endPoint, useSSL } = minioRest;
 | 
			
		||||
export const minioUrl = `http${useSSL ? 's' : ''}://${endPoint}:${port || 9000}`;
 | 
			
		||||
export const minioResources = `${minioUrl}/resources`;
 | 
			
		||||
export const minioClient = new Client(minioRest);
 | 
			
		||||
export { bucketName };
 | 
			
		||||
if (!minioClient) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								src/module/proxy/http-proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/module/proxy/http-proxy.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
import { pipeline } from 'stream';
 | 
			
		||||
import { promisify } from 'util';
 | 
			
		||||
import { bucketName, minioClient, minioResources } from '../minio.ts';
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import { IncomingMessage, ServerResponse } from 'http';
 | 
			
		||||
import http from 'http';
 | 
			
		||||
import https from 'https';
 | 
			
		||||
import { UserApp } from '../get-user-app.ts';
 | 
			
		||||
 | 
			
		||||
const pipelineAsync = promisify(pipeline);
 | 
			
		||||
 | 
			
		||||
export async function downloadFileFromMinio(fileUrl: string, destFile: string) {
 | 
			
		||||
  const objectName = fileUrl.replace(minioResources + '/', '');
 | 
			
		||||
  const objectStream = await minioClient.getObject(bucketName, objectName);
 | 
			
		||||
  const destStream = fs.createWriteStream(destFile);
 | 
			
		||||
  await pipelineAsync(objectStream, destStream);
 | 
			
		||||
  console.log(`minio File downloaded to ${minioResources}/${objectName} \n ${destFile}`);
 | 
			
		||||
}
 | 
			
		||||
export async function minioProxy(
 | 
			
		||||
  req: IncomingMessage,
 | 
			
		||||
  res: ServerResponse,
 | 
			
		||||
  opts: {
 | 
			
		||||
    proxyUrl: string;
 | 
			
		||||
    userApp: UserApp;
 | 
			
		||||
    createNotFoundPage: (msg?: string) => any;
 | 
			
		||||
  },
 | 
			
		||||
) {
 | 
			
		||||
  const fileUrl = opts.proxyUrl;
 | 
			
		||||
  const { userApp, createNotFoundPage } = opts;
 | 
			
		||||
  const objectName = fileUrl.replace(minioResources + '/', '');
 | 
			
		||||
  try {
 | 
			
		||||
    const stat = await minioClient.statObject(bucketName, objectName);
 | 
			
		||||
    if (stat.size === 0) {
 | 
			
		||||
      return createNotFoundPage('Invalid proxy url');
 | 
			
		||||
    }
 | 
			
		||||
    const contentLength = stat.size;
 | 
			
		||||
    const etag = stat.etag;
 | 
			
		||||
    const lastModified = stat.lastModified.toISOString();
 | 
			
		||||
    // console.log('contentType', stat.metaData);
 | 
			
		||||
    res.writeHead(200, {
 | 
			
		||||
      'Content-Length': contentLength,
 | 
			
		||||
      etag,
 | 
			
		||||
      'last-modified': lastModified,
 | 
			
		||||
      ...stat.metaData,
 | 
			
		||||
    });
 | 
			
		||||
    const objectStream = await minioClient.getObject(bucketName, objectName);
 | 
			
		||||
    objectStream.pipe(res, { end: true });
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(`Proxy request error: ${error.message}`);
 | 
			
		||||
    userApp.clearCacheData();
 | 
			
		||||
    return createNotFoundPage('Invalid proxy url');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const httpProxy = async (
 | 
			
		||||
  req: IncomingMessage,
 | 
			
		||||
  res: ServerResponse,
 | 
			
		||||
  opts: {
 | 
			
		||||
    proxyUrl: string;
 | 
			
		||||
    userApp: UserApp;
 | 
			
		||||
    createNotFoundPage: (msg?: string) => any;
 | 
			
		||||
  },
 | 
			
		||||
) => {
 | 
			
		||||
  const { proxyUrl, userApp, createNotFoundPage } = opts;
 | 
			
		||||
  if (proxyUrl.startsWith(minioResources)) {
 | 
			
		||||
    return minioProxy(req, res, opts);
 | 
			
		||||
  }
 | 
			
		||||
  let protocol = proxyUrl.startsWith('https') ? https : http;
 | 
			
		||||
  // 代理
 | 
			
		||||
  const proxyReq = protocol.request(proxyUrl, (proxyRes) => {
 | 
			
		||||
    res.writeHead(proxyRes.statusCode, {
 | 
			
		||||
      ...proxyRes.headers,
 | 
			
		||||
    });
 | 
			
		||||
    if (proxyRes.statusCode === 404) {
 | 
			
		||||
      userApp.clearCacheData();
 | 
			
		||||
      return createNotFoundPage('Invalid proxy url');
 | 
			
		||||
    }
 | 
			
		||||
    if (proxyRes.statusCode === 302) {
 | 
			
		||||
      res.writeHead(302, { Location: proxyRes.headers.location });
 | 
			
		||||
      return res.end();
 | 
			
		||||
    }
 | 
			
		||||
    proxyRes.pipe(res, { end: true });
 | 
			
		||||
  });
 | 
			
		||||
  proxyReq.on('error', (err) => {
 | 
			
		||||
    console.error(`Proxy request error: ${err.message}`);
 | 
			
		||||
    userApp.clearCacheData();
 | 
			
		||||
  });
 | 
			
		||||
  proxyReq.end();
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user