file-store.js 1.15 KB
/**
 * 交付文件的内容存储:本地磁盘目录,一个文件一个对象,文件名就是平台生成的 file_id。
 * ponytail: 单机磁盘,多实例或换机器会丢;上 stage / 生产前换成对象存储(S3 / OSS)实现同样的 put / get。
 */
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import path from 'node:path'

const FILE_ID = /^f_[0-9a-f-]{36}$/

/**
 * @param {{ dir: string }} opts
 */
export function createFileStore({ dir }) {
  /** @param {string} file_id */
  function pathOf(file_id) {
    // file_id 由平台生成;这里再校验一次,保证任何输入都拼不出目录外的路径。
    if (!FILE_ID.test(file_id)) throw new Error(`file store: invalid file id: ${file_id}`)
    return path.join(dir, file_id)
  }

  return {
    /**
     * @param {string} file_id
     * @param {Buffer} body
     */
    async put(file_id, body) {
      await mkdir(dir, { recursive: true })
      await writeFile(pathOf(file_id), body, { flag: 'wx' })
    },
    /**
     * @param {string} file_id
     * @returns {Promise<Buffer>}
     */
    async get(file_id) {
      return readFile(pathOf(file_id))
    },
  }
}