Skip to content

Commit

Permalink
Feature/0.4.0 (#6)
Browse files Browse the repository at this point in the history
* chore: 更新 gitignore

* feat: demo 包使用 typescript 运行

* feat: 新增路由基准路径的配置项

* refactor: 调整代码中的导出方式

* feat: 添加渲染异常对象的可选配置

* refactor: 路由系统泛型类型重构

* chore: 新增 setup 脚本安装 demo 目录的依赖

* feat: 新增 CommonError 的单元测试

* doc: 更新中间件的文档

* refactor: 统一从 typing 导入公用的接口声明

* fix: 修复配置 base 后没有使用 base path 访问接口也能成功响应的问题

* feat: 导出 CommonError 类供应用层使用

* chore: 同步 @types/node 的版本

* chore: Update package-lock.json

* feat: 新增对 HEAD 方法的支持

* fix: 修复 MD5 函数重复 digest 的问题

* fix: 请求 url 前缀不包含 base 时返回空 handler

* fix: 消除前导问号,并对 key value 进行 URL 解码
  • Loading branch information
divasatanica authored Mar 16, 2022
1 parent e24e97f commit dde2c2c
Show file tree
Hide file tree
Showing 40 changed files with 4,824 additions and 4,681 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ dist/
lib/
public/
*-debug.log
coverage
coverage
.DS_Store
167 changes: 0 additions & 167 deletions demo/index.js

This file was deleted.

14 changes: 14 additions & 0 deletions demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "demo",
"version": "1.0.0",
"private": true,
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@types/node": "^17.0.21",
"typescript": "^4.6.2"
},
"scripts": {
"start": "tsc && node dist/index.js"
}
}
164 changes: 164 additions & 0 deletions demo/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import * as fs from 'fs';
import * as path from 'path';
import { Server, Middlewares, Router, RouterMapFactory, CommonError } from '../../packages/auf';

const Config = {
chunkSize: 5 * 1024 * 1024,
publicDir: path.resolve(__dirname, '../public')
};

const serverTag = '[auf]';
const errorTag = 'Error:';
const port = 60000;
const timeout = 5000;
const callback = () => {
console.log(serverTag, 'Server Listening on', port);
}
const errorHandler = (e: Error) => {
console.error(serverTag, errorTag, e.message, '\n', e.stack);
}
const routerMap = RouterMapFactory(/* base= */'/api');
const fsredirPromise = (path: string) => new Promise<string[]>((resolve, reject) => {
fs.readdir(path, (err, files) => {
if (err) {
reject(new CommonError({
message: err.message,
statusCode: 500,
statusMessage: 'File not exists'
}));
}
resolve(files);
});
});

const server = new Server({
port,
assetsRoot: Config.publicDir
});

routerMap.get('/', async (ctx, next) => {
ctx.body = '';
next && await next(ctx);
});

routerMap.get('/upload/config', async (ctx, next) => {
ctx.body = JSON.stringify(Object.assign({}, { chunkSize: Config.chunkSize }))
// @ts-ignore
next && await next(ctx);
});

routerMap.head('/upload/config', async (ctx, next) => {
ctx.body = JSON.stringify(Object.assign({}, { chunkSize: Config.chunkSize }));
next && await next(ctx);
});

routerMap.get('/upload/chunkIndex', async (ctx, next) => {
const res = await fsredirPromise(Config.publicDir);
// const res = [];
const hash = ctx.query.hash;
const fileWithHash = res.filter(file => file.indexOf(hash) === 0)
ctx.body = JSON.stringify({
success: true,
message: '',
data: fileWithHash.length
});
next && await next(ctx);
});

routerMap.post('/upload', async (ctx, next) => {
const body = ctx.reqBody;
const { files, index, filename: _filename, chunkCount, fileHash } = body;
const _file = files[0];
const { file } = _file;
const filename = decodeURIComponent(_filename);

const stream = fs.createWriteStream(path.resolve(Config.publicDir, `${fileHash}-${index}`));
stream.write(file, 'binary');

ctx.body = JSON.stringify({ msg: 'success', success: true, data: (Number(index) + 1) / Number(chunkCount) });
stream.end();
stream.on('finish', async () => {
console.log('Writing Finished')
if (Number(chunkCount) === Number(index) + 1) {
const mergeStream = fs.createWriteStream(path.resolve(Config.publicDir, filename));
// const chunkArr = Array.from({ length: chunkCount }).map((_, index) => index);

let promise = new Promise<number>((resolve) => {
const fd = path.resolve(Config.publicDir, `${fileHash}-${0}`)
const readData = fs.readFileSync(fd)

const writable = mergeStream.write(readData, 'binary');

if (!writable) {
console.log('Waiting Drain Event For', index);
const drainListener = () => {
resolve(1);
fs.existsSync(fd) && fs.unlink(fd, err => err && console.error(err));
mergeStream.removeListener('drain', drainListener);
}
mergeStream.on('drain', drainListener)
}
})

let q = 0;
while (q < chunkCount - 1) {
promise = promise.then(index => {
return new Promise<number>(resolve => {
const fd = path.resolve(Config.publicDir, `${fileHash}-${index}`)
const readData = fs.readFileSync(fd)

const writable = mergeStream.write(readData, 'binary');

if (!writable) {
console.log('Waiting Drain Event For', index);
const drainListener = () => {
resolve(index + 1);
mergeStream.removeListener('drain', drainListener);
}
mergeStream.on('drain', drainListener)
} else {
resolve(index + 1)
}

fs.unlink(fd, err => err && console.error(err))
})
})
q ++;
}

}
});
next && await next(ctx);
});

const CORS = function () {
return async function (ctx, next) {
await next(ctx)

const { res } = ctx
// console.log(res)
res.setHeader('Access-Control-Allow-Origin', '*')
}
}

server.applyMiddleware([
CORS(),
Middlewares.ErrorBoundary({
errorHandler,
renderError: true
}),
Middlewares.Timeout({ timeout }),
Middlewares.Logger(console),
Middlewares.StaticRoutes({
fileSystem: fs
}),
Middlewares.BodyParser(),
Router()
])


try {
server.setup(callback);
} catch (e) {
console.error(e.message);
}
34 changes: 34 additions & 0 deletions demo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "es5",
"allowSyntheticDefaultImports": true, // 允许你使用 ES2015 默认的 imports 风格
"sourceMap": true, // 使 TypeScript 生成 sourcemaps
"strictNullChecks": true,
"moduleResolution": "node",
"noUnusedLocals": true,
"noUnusedParameters": true,
"baseUrl": ".",
"outDir": "./dist",
"declaration": true,
"declarationDir": "./dist/types",
"rootDir": "src"
},
"include": [
"src/**/*.ts",
"src/*.ts"
],
"exclude": [
"node_modules", // 这个目录下的代码不会被 typescript 处理
"lib",
"webpack",
"es",
"dist"
],
"lib": [
"esnext",
"es2015",
"dom",
"dom.iterable",
"scripthost"
]
}
Loading

0 comments on commit dde2c2c

Please sign in to comment.