refactor: async io handle
This commit is contained in:
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user