refactor: async io handle

This commit is contained in:
Innei
2022-03-08 20:21:25 +08:00
committed by
parent d0e680a2a2
commit d794f8cd9a
5 changed files with 52 additions and 36 deletions

View File

@@ -31,11 +31,11 @@ export class EmailOptionController {
}
@Put('/template/reply')
writeEmailReplyTemplate(
async writeEmailReplyTemplate(
@Query() { type }: ReplyEmailTypeDto,
@Body() body: ReplyEmailBodyDto,
) {
this.emailService.writeTemplate(
await this.emailService.writeTemplate(
type === 'guest' ? ReplyMailType.Guest : ReplyMailType.Owner,
body.source,
)

View File

@@ -51,6 +51,9 @@ async function handler(context, require) {}
- 只传入 env, 只读
- 可传入 stdout, stderr 但是有无必要?
TODO: 捕获 safeEval 报错
## 全局上下文
1. req, res
@@ -76,9 +79,10 @@ Get 公开接口
# Break
Get /:id 现需要鉴权
Get /:id 现需要鉴权, 不计算 data 属性
Get /:reference/:name 对外公开
<!-- 请求响应: JSON, 原始类型会被挂载到 `{data: }`. 会进行 JSON snakecase 处理 -->
请求响应: raw data, http bypass
请求响应: raw data, http bypass

View File

@@ -5,9 +5,11 @@ import {
NotFoundException,
} from '@nestjs/common'
import { isURL } from 'class-validator'
import fs from 'fs/promises'
import { load } from 'js-yaml'
import { InjectModel } from 'nestjs-typegoose'
import type PKG from '~/../package.json'
import { AssetService } from '~/processors/helper/helper.asset.service'
import { UniqueArray } from '~/ts-hepler/unique'
import { safeEval } from '~/utils/safe-eval.util'
import { isBuiltinModule } from '~/utils/sys.util'
@@ -18,6 +20,7 @@ export class SnippetService {
constructor(
@InjectModel(SnippetModel)
private readonly snippetModel: MongooseModel<SnippetModel>,
private readonly assetService: AssetService,
) {}
get model() {
@@ -85,25 +88,39 @@ export class SnippetService {
async injectContextIntoServerlessFunctionAndCall(model: SnippetModel) {
const { raw: functionString } = model
const logger = new Logger('serverless-function')
const document = await this.model.findById(model.id)
const global = {
context: {
model,
document: await this.model.findById(model.id),
document,
name: model.name,
reference: model.reference,
// TODO
// write file to asset
writeAsset: async (
path: string,
data: any,
options: Parameters<typeof fs.writeFile>[2],
) => {
return await this.assetService.writeUserCustomAsset(
path,
data,
options,
)
},
// read file to asset
readAsset: async (
path: string,
options: Parameters<typeof fs.readFile>[1],
) => {
return await this.assetService.getAsset(path, options)
},
},
// inject global
__dirname,
// inject some zx utils
$,
cd,
sleep,
nothrow,
question,
fetch,
// inject logger
@@ -121,7 +138,7 @@ export class SnippetService {
) {
const res = await fetch(id)
const text = await res.text()
return safeEval(text)
return await safeEval(text)
}
// 2. if application third part lib
@@ -150,7 +167,6 @@ export class SnippetService {
'snakecase-keys',
'ua-parser-js',
'xss',
'zx',
]
if (allowedThirdPartLibs.includes(id as any)) {
@@ -174,7 +190,7 @@ export class SnippetService {
return await safeEval(
`${functionString}; return handler(context, require)`,
global,
{ ...global, global },
)
}
@@ -192,7 +208,7 @@ export class SnippetService {
async getSnippetById(id: string) {
const doc = await this.model.findById(id).lean()
return this.attachSnippet(doc)
return doc
}
/**

View File

@@ -4,9 +4,9 @@
* @description 用于获取静态资源的服务
*/
import { Injectable, Logger } from '@nestjs/common'
import fs from 'fs'
import { existsSync } from 'fs'
import fs from 'fs/promises'
import path, { join } from 'path'
import { promisify } from 'util'
import { USER_ASSET_DIR } from '~/constants/path.constant'
import { HttpService } from './helper.http.service'
@@ -27,7 +27,7 @@ export class AssetService {
'https://cdn.jsdelivr.net/gh/mx-space/assets@master/'
private checkRoot() {
if (!fs.existsSync(this.embedAssetPath)) {
if (!existsSync(this.embedAssetPath)) {
return false
}
return true
@@ -43,7 +43,7 @@ export class AssetService {
return false
}
path = join(this.embedAssetPath, path)
if (!fs.existsSync(path)) {
if (!existsSync(path)) {
return false
}
return true
@@ -51,17 +51,17 @@ export class AssetService {
private async getUserCustomAsset(
path: string,
options: Parameters<typeof fs.readFileSync>[1],
options: Parameters<typeof fs.readFile>[1],
) {
if (fs.existsSync(join(USER_ASSET_DIR, path))) {
return await promisify(fs.readFile)(join(USER_ASSET_DIR, path), options)
if (existsSync(join(USER_ASSET_DIR, path))) {
return await fs.readFile(join(USER_ASSET_DIR, path), options)
}
return null
}
public async getAsset(
path: string,
options: Parameters<typeof fs.readFileSync>[1],
options: Parameters<typeof fs.readFile>[1],
) {
// 想找用户自定义的资源入口
if (await this.getUserCustomAsset(path, options)) {
@@ -74,43 +74,39 @@ export class AssetService {
this.onlineAssetPath + path,
)
fs.mkdirSync(
await fs.mkdir(
(() => {
const p = join(this.embedAssetPath, path).split('/')
return p.slice(0, p.length - 1).join('/')
})(),
{ recursive: true },
)
await promisify(fs.writeFile)(
join(this.embedAssetPath, path),
data,
options,
)
await fs.writeFile(join(this.embedAssetPath, path), data, options)
return data
} catch (e) {
this.logger.error('本地资源不存在,线上资源无法拉取')
throw e
}
}
return promisify(fs.readFile)(join(this.embedAssetPath, path), options)
return fs.readFile(join(this.embedAssetPath, path), options)
}
public writeUserCustomAsset(
public async writeUserCustomAsset(
path: string,
data: any,
options: Parameters<typeof fs.writeFileSync>[2],
options: Parameters<typeof fs.writeFile>[2],
) {
fs.mkdirSync(
await fs.mkdir(
(() => {
const p = join(USER_ASSET_DIR, path).split('/')
return p.slice(0, p.length - 1).join('/')
})(),
{ recursive: true },
)
fs.writeFileSync(join(USER_ASSET_DIR, path), data, options)
return fs.writeFile(join(USER_ASSET_DIR, path), data, options)
}
public async removeUserCustomAsset(path: string) {
return promisify(fs.unlink)(join(USER_ASSET_DIR, path))
return fs.unlink(join(USER_ASSET_DIR, path))
}
}

View File

@@ -53,7 +53,7 @@ export class EmailService {
}
}
writeTemplate(type: ReplyMailType, source: string) {
async writeTemplate(type: ReplyMailType, source: string) {
switch (type) {
case ReplyMailType.Guest:
return this.assetService.writeUserCustomAsset(