Skip to content

Commit c7e45cb

Browse files
authored
refactor: rewrite md-cli with express (#957)
* refactor: rewrite md-cli with express for mockm's security problem * refactor: remove useless method * feat: local upload fallback
1 parent db7f9a8 commit c7e45cb

File tree

6 files changed

+357
-2987
lines changed

6 files changed

+357
-2987
lines changed

packages/md-cli/index.js

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,57 @@
11
#!/usr/bin/env node
22

3-
const { ProcessManager } = require(`@wll8/process-manager`);
4-
const {
5-
handleSpace,
3+
import { readFileSync } from 'fs'
4+
import getPort from 'get-port'
5+
import {
66
colors,
77
parseArgv,
8-
} = require(`./util.js`)
8+
} from './util.js'
9+
import { createServer } from './server.js'
10+
11+
const packageJson = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'))
912

1013
const arg = parseArgv()
1114

12-
new Promise(async () => {
13-
const getPort = (await import("get-port")).default;
14-
15-
let { port = 8800, testPort, replayPort } = arg
16-
port = Number(port)
17-
;[port, testPort, replayPort] = await Promise.all([port, port+1, port+2].map(item => getPort({port: item}) )).catch(err => console.log(`err`, err))
18-
const line = Object.entries({
19-
...arg,
20-
proxy: `https://doocs-md.pages.dev`,
21-
port,
22-
testPort,
23-
replayPort,
24-
'--config': handleSpace(`${__dirname}/mm.config.js`),
25-
}).map(([key, val]) => `${key}=${val}`)
26-
const cliArg = [handleSpace(`${__dirname}/node_modules/mockm/run.js`), `--log-line`, ...line]
27-
console.log(`doocs/md-cli v${require(`./package.json`).version}`)
28-
console.log(`服务启动中...`)
29-
const cp = new ProcessManager(cliArg)
30-
cp.on(`stdout`, (info = ``) => {
31-
if(info.match(`:${port}/`)) {
15+
async function startServer() {
16+
try {
17+
let { port = 8800 } = arg
18+
port = Number(port)
19+
20+
port = await getPort({ port }).catch(_ => {
21+
console.log(`端口 ${port} 被占用,正在寻找可用端口...`)
22+
return getPort()
23+
})
24+
25+
console.log(`doocs/md-cli v${packageJson.version}`)
26+
console.log(`服务启动中...`)
27+
28+
const app = createServer(port)
29+
30+
app.listen(port, '127.0.0.1', () => {
3231
console.log(`服务已启动:`)
3332
console.log(`打开链接 ${colors.green(`http://127.0.0.1:${port}/md/`)} 即刻使用吧~`)
34-
}
35-
if(info.match(`Port is occupied`)) {
36-
process.exit()
37-
}
38-
})
39-
}).catch(err => console.log(err))
33+
console.log(``)
34+
35+
const { spaceId, clientSecret } = arg
36+
if (spaceId && clientSecret) {
37+
console.log(`${colors.green('✅ 云存储已配置,可通过自定义代码上传图片')}`)
38+
}
39+
})
40+
41+
process.once('SIGINT', () => {
42+
console.log('\n服务器已关闭')
43+
process.exit(0)
44+
})
45+
46+
process.once('SIGTERM', () => {
47+
console.log('\n服务器已关闭')
48+
process.exit(0)
49+
})
50+
51+
} catch (err) {
52+
console.error('启动服务器失败:', err)
53+
process.exit(1)
54+
}
55+
}
56+
57+
startServer()

packages/md-cli/mm.config.js

Lines changed: 0 additions & 55 deletions
This file was deleted.

packages/md-cli/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "@doocs/md-cli",
33
"version": "0.1.3",
4+
"type": "module",
45
"description": "WeChat Markdown Editor | 一款高度简洁的微信 Markdown 编辑器:支持 Markdown 语法、自定义主题样式、内容管理、多图床、AI 助手等特性",
56
"main": "index.js",
67
"scripts": {
@@ -13,17 +14,18 @@
1314
"dist",
1415
"public",
1516
"index.js",
16-
"mm.config.js",
17+
"server.js",
1718
"util.js"
1819
],
1920
"keywords": [],
2021
"author": "wll8",
2122
"license": "ISC",
2223
"dependencies": {
23-
"@wll8/process-manager": "^1.0.4",
24+
"express": "^5.1.0",
25+
"multer": "^2.0.2",
26+
"http-proxy-middleware": "^3.0.5",
2427
"form-data": "4.0.4",
2528
"get-port": "7.1.0",
26-
"mockm": "^1.1.27-alpha.12",
2729
"node-fetch": "^3.3.2"
2830
}
2931
}

packages/md-cli/server.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import express from 'express'
2+
import multer from 'multer'
3+
import path from 'path'
4+
import fs from 'fs'
5+
import { fileURLToPath } from 'url'
6+
import { dirname } from 'path'
7+
import { createProxyMiddleware } from 'http-proxy-middleware'
8+
import {
9+
dcloud,
10+
parseArgv,
11+
colors
12+
} from './util.js'
13+
14+
const __filename = fileURLToPath(import.meta.url)
15+
const __dirname = dirname(__filename)
16+
const arg = parseArgv()
17+
18+
// unicloud 服务空间配置
19+
const spaceInfo = {
20+
spaceId: ``,
21+
clientSecret: ``,
22+
...arg,
23+
}
24+
25+
/**
26+
* 创建 Express 服务器
27+
* @param {number} port - 服务器端口
28+
*/
29+
export function createServer(port = 8800) {
30+
const app = express()
31+
32+
// 确保上传目录存在
33+
const uploadDir = path.join(__dirname, 'public/upload')
34+
if (!fs.existsSync(uploadDir)) {
35+
fs.mkdirSync(uploadDir, { recursive: true })
36+
}
37+
38+
// 配置 multer 用于文件上传
39+
const storage = multer.diskStorage({
40+
destination: (req, file, cb) => {
41+
cb(null, uploadDir)
42+
},
43+
filename: (req, file, cb) => {
44+
cb(null, file.originalname)
45+
}
46+
})
47+
48+
const upload = multer({ storage })
49+
50+
// 中间件
51+
app.use(express.json())
52+
app.use(express.urlencoded({ extended: true }))
53+
54+
app.use('/public', express.static(path.join(__dirname, 'public')))
55+
56+
// 文件上传 API
57+
app.post('/upload', upload.single('file'), async (req, res) => {
58+
try {
59+
if (!req.file) {
60+
return res.status(400).json({ error: 'No file uploaded' })
61+
}
62+
63+
const file = req.file
64+
let url = `http://127.0.0.1:${port}/public/upload/${file.filename}`
65+
66+
try {
67+
if (spaceInfo.spaceId && spaceInfo.clientSecret) {
68+
url = await dcloud(spaceInfo)({
69+
name: file.originalname,
70+
file: fs.createReadStream(file.path)
71+
})
72+
73+
// 上传成功后删除本地临时文件
74+
fs.unlinkSync(file.path)
75+
console.log('文件已上传到云端:', url)
76+
} else {
77+
console.log(`${colors.yellow('未配置云存储,降级到本地存储')}`)
78+
}
79+
} catch (err) {
80+
// 云上传失败,降级到本地存储
81+
console.log('云存储上传失败,降级到本地存储:', err.message)
82+
}
83+
84+
res.json({ url })
85+
} catch (error) {
86+
console.error('Upload error:', error)
87+
res.status(500).json({ error: error.message })
88+
}
89+
})
90+
91+
app.get('/', (_, res) => {
92+
res.redirect('/md/')
93+
})
94+
95+
console.log('代理到: https://doocs-md.pages.dev')
96+
app.use(createProxyMiddleware({
97+
target: 'https://doocs-md.pages.dev',
98+
changeOrigin: true,
99+
onError: (err, req, res) => {
100+
console.error(`代理错误 ${req.path}:`, err.message)
101+
res.status(502).send('代理服务暂不可用,请检查网络连接')
102+
},
103+
}))
104+
105+
return app
106+
}

0 commit comments

Comments
 (0)