diff --git a/api/useGetApi.js b/api/useGetApi.js new file mode 100644 index 0000000..64f18f7 --- /dev/null +++ b/api/useGetApi.js @@ -0,0 +1,48 @@ +import express from "express"; +import path from "path"; +import fs from "fs"; +import { staticPath, api_get } from "../config.js"; + +export default function useGetApi(app) { + // 不存在文件与文件夹同名的问题 + app.use(api_get, (req, res, next) => { + const decodedPath = decodeURIComponent(req.path); + const directoryPath = path.join(staticPath, decodedPath); + fs.stat(directoryPath, (err, stats) => { + if (err) { + console.log(err, directoryPath); + // return res.status(500).json({ error: "Unable to access path" }); + return next(); + } + + if (stats.isDirectory()) { + fs.readdir(directoryPath, (err, files) => { + if (err) { + console.log(err, directoryPath); + return res.status(500).json({ error: "Unable to scan directory" }); + } + const fileDetails = files.map(file => { + const filePath = path.join(directoryPath, file); + const stats = fs.statSync(filePath); + return { + name: file, + size: stats.isDirectory() ? undefined : stats.size, + type: stats.isDirectory() ? "directory" : "file", + stats: { + atimeMs: stats.atimeMs, + birthtimeMs: stats.birthtimeMs, + ctimeMs: stats.ctimeMs, + mtimeMs: stats.mtimeMs + } + }; + }); + res.json(fileDetails); + }); + } else { + next(); + } + }); + }); + + app.use(api_get, express.static(staticPath)); +} diff --git a/api/useUploadApi.js b/api/useUploadApi.js new file mode 100644 index 0000000..f83ee10 --- /dev/null +++ b/api/useUploadApi.js @@ -0,0 +1,34 @@ +import path from "path"; +import fs from "fs"; +import multer from "multer"; +import { api_upload, staticPath } from "../config.js"; + +const storage = multer.memoryStorage(); +const upload = multer({ storage: storage }).single('file'); + +export default function useUploadApi(app) { + app.post(api_upload, upload, (req, res) => { + const decodedPath = decodeURIComponent(req.path).substring(8); + const savePath = path.join(staticPath, decodedPath, req.file.originalname) + // 覆盖写or追加写 + const oprateType = req.body.oprateType === 'write' ? 'write' : 'append' + const data = req.file.buffer + if (oprateType === 'write') { + // 覆盖写入 + fs.writeFile(savePath, data, (err) => { + if (err) { + return res.status(500).json({ message: 'failed', error: err }); + } + res.status(200).json({ message: 'success' }); + }); + } else { + // 追加写入 + fs.appendFile(savePath, data, (err) => { + if (err) { + return res.status(500).json({ message: 'failed', error: err }); + } + res.status(200).json({ message: 'success' }); + }); + } + }); +} diff --git a/config.js b/config.js new file mode 100644 index 0000000..d10463b --- /dev/null +++ b/config.js @@ -0,0 +1,10 @@ +import path from "path"; + + +export const staticPath = path.join("./static"); +export const port = 17705; + +export const api_get = `/${"get"}`; +export const api_upload = `/${"upload"}/*`; + +export default { staticPath, port, api_get, api_upload } \ No newline at end of file diff --git a/index.js b/index.js index 5c3bcac..e0df84e 100644 --- a/index.js +++ b/index.js @@ -1,61 +1,24 @@ import express from "express"; import os from "os"; -import path from "path"; import cors from "cors"; import fs from "fs"; +import useGetApi from "./api/useGetApi.js"; +import Config from "./config.js"; +import useUploadApi from "./api/useUploadApi.js"; -if (!fs.existsSync("./static")) { - fs.mkdirSync("./static"); + +const { staticPath, port, api_get } = Config; + +if (!fs.existsSync(staticPath)) { + fs.mkdirSync(staticPath); } -const staticPath = path.join("./static"); -const port = 17705; -const prev = `/${"get"}`; const app = express(); app.use(cors()); -// 不存在文件与文件夹同名的问题 -app.use(prev, (req, res, next) => { - const decodedPath = decodeURIComponent(req.path); - const directoryPath = path.join(staticPath, decodedPath); - fs.stat(directoryPath, (err, stats) => { - if (err) { - console.log(err, directoryPath); - // return res.status(500).json({ error: "Unable to access path" }); - return next() - } - - if (stats.isDirectory()) { - fs.readdir(directoryPath, (err, files) => { - if (err) { - console.log(err, directoryPath); - return res.status(500).json({ error: "Unable to scan directory" }); - } - const fileDetails = files.map(file => { - const filePath = path.join(directoryPath, file); - const stats = fs.statSync(filePath); - return { - name: file, - size: stats.isDirectory() ? undefined : stats.size, - type: stats.isDirectory() ? "directory" : "file", - stats: { - atimeMs: stats.atimeMs, - birthtimeMs: stats.birthtimeMs, - ctimeMs: stats.ctimeMs, - mtimeMs: stats.mtimeMs - } - }; - }); - res.json(fileDetails); - }); - } else { - next(); - } - }); -}); - -app.use(prev, express.static(staticPath)); +useGetApi(app); +useUploadApi(app); app.listen(port, "::", () => { const interfaces = os.networkInterfaces(); @@ -68,7 +31,7 @@ app.listen(port, "::", () => { console.log(`以下地址访问文件/文件夹:`); for (const name of Object.keys(interfaces)) { for (const iface of interfaces[name]) { - iface.family === "IPv6" ? console.log(`http://[${iface.address}]:${port}${prev}`) : console.log(`http://${iface.address}:${port}${prev}`); + iface.family === "IPv6" ? console.log(`http://[${iface.address}]:${port}${api_get}`) : console.log(`http://${iface.address}:${port}${api_get}`); } } }); diff --git a/package.json b/package.json index 088ce7f..7f29ac9 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "license": "ISC", "dependencies": { "cors": "^2.8.5", - "express": "^4.19.2" + "express": "^4.19.2", + "multer": "1.4.5-lts.1" }, "devDependencies": { "@vercel/ncc": "^0.38.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8f131c..a43b488 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: express: specifier: ^4.19.2 version: 4.19.2 + multer: + specifier: 1.4.5-lts.1 + version: 1.4.5-lts.1 devDependencies: '@vercel/ncc': specifier: ^0.38.1 @@ -32,6 +35,9 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} @@ -39,6 +45,13 @@ packages: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -47,6 +60,10 @@ packages: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -62,6 +79,9 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -164,6 +184,9 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -188,12 +211,23 @@ packages: engines: {node: '>=4'} hasBin: true + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multer@1.4.5-lts.1: + resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} + engines: {node: '>= 6.0.0'} + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -217,6 +251,9 @@ packages: path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -233,6 +270,12 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -262,6 +305,13 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -270,6 +320,9 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + uglify-js@3.19.1: resolution: {integrity: sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A==} engines: {node: '>=0.8.0'} @@ -279,6 +332,9 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -287,6 +343,10 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + snapshots: '@vercel/ncc@0.38.1': {} @@ -296,6 +356,8 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + append-field@1.0.0: {} + array-flatten@1.1.1: {} body-parser@1.20.2: @@ -315,6 +377,12 @@ snapshots: transitivePeerDependencies: - supports-color + buffer-from@1.1.2: {} + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + bytes@3.1.2: {} call-bind@1.0.7: @@ -325,6 +393,13 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + concat-stream@1.6.2: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 @@ -335,6 +410,8 @@ snapshots: cookie@0.6.0: {} + core-util-is@1.0.3: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -462,6 +539,8 @@ snapshots: ipaddr.js@1.9.1: {} + isarray@1.0.0: {} + media-typer@0.3.0: {} merge-descriptors@1.0.1: {} @@ -476,10 +555,26 @@ snapshots: mime@1.6.0: {} + minimist@1.2.8: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + ms@2.0.0: {} ms@2.1.3: {} + multer@1.4.5-lts.1: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + negotiator@0.6.3: {} object-assign@4.1.1: {} @@ -494,6 +589,8 @@ snapshots: path-to-regexp@0.1.7: {} + process-nextick-args@2.0.1: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -512,6 +609,18 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} @@ -563,6 +672,12 @@ snapshots: statuses@2.0.1: {} + streamsearch@1.1.0: {} + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + toidentifier@1.0.1: {} type-is@1.6.18: @@ -570,10 +685,16 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + typedarray@0.0.6: {} + uglify-js@3.19.1: {} unpipe@1.0.0: {} + util-deprecate@1.0.2: {} + utils-merge@1.0.1: {} vary@1.1.2: {} + + xtend@4.0.2: {}