Files

1 line
7.3 KiB
JavaScript
Raw Permalink Normal View History

2025-01-04 00:34:03 +01:00
import crypto from"node:crypto";import fs from"node:fs";import path from"node:path";import LocalFileStorage from"./local.mjs";import S3FileStorage from"./s3.mjs";import{HTML_FILE_EXTENSIONS,MEDIA_MIME_TYPES,UPLOADABLE_FILE_EXTENSIONS}from"../../common/constants.mjs";import{getProperty,mergeObject,parseS3URL}from"../../common/utils/helpers.mjs";import unzipper from"unzipper";export default class Files{constructor(t){this.storages={data:new LocalFileStorage("data",paths.data),public:new LocalFileStorage("public",paths.public),s3:S3FileStorage.fromConfig("s3",t.awsConfig)},this.configuration=this._loadConfig()}static STORAGE_CONFIGURATION_FILENAME="storage.json";_loadConfig(){const t=path.join(paths.config,Files.STORAGE_CONFIGURATION_FILENAME);return fs.existsSync(t)?JSON.parse(fs.readFileSync(t,"utf8")):{}}get availableStorageNames(){return Object.entries(this.storages).reduce(((t,e)=>(e[1]&&t.push(e[0]),t)),[])}getClientConfig(t){const e=this.availableStorageNames.filter((e=>{if(!t||t.hasRole("ASSISTANT"))return!0;const{configuration:s}=this.storages[e];return!0!==s[""]?.private})),s=this.storages.s3;return{storages:e,s3:s?{endpoint:s.endpoint,buckets:s.buckets}:null}}static async copyDirectory(t,e,{onProgress:s=null,onError:r=null,ignore:a=[],_root:i=!0}={}){i&&(a=a.map((e=>path.join(t,e)))),await fs.promises.mkdir(e,{recursive:!0});const o=fs.readdirSync(t);for(let i of o){let o=path.join(t,i),n=path.join(e,i);if(!a.includes(o))if(fs.lstatSync(o).isDirectory())await this.copyDirectory(o,n,{onProgress:s,onError:r,ignore:a,_root:!1});else{try{await fs.promises.copyFile(o,n)}catch(t){if(!(r instanceof Function))throw t;r(o,n,t)}s instanceof Function&&s(o,n)}}}static async getDirectorySize(t){if(!fs.existsSync(t))return;let e=0;const s=async t=>{const r=[];for(const a of await fs.promises.readdir(t,{withFileTypes:!0})){const i=path.join(t,a.name);a.isDirectory()?r.push(s(i)):r.push(fs.promises.stat(i).then((t=>e+=t.size)))}await Promise.all(r)};return await s(t),e}static getDirectorySizeSync(t){if(!fs.existsSync(t))return;const e=(t,s)=>{for(const r of fs.readdirSync(t,{withFileTypes:!0})){const a=path.join(t,r.name);r.isDirectory()?s=e(a,s):s+=fs.statSync(a).size}return s};return e(t,0)}static async processArchive(t,e,s){const r=process;let a,i;r.noAsar=!0;try{a=await unzipper.Open.file(t),i=a.files.length;let r=0;for(const t of a.files){t.path=t.path.replace(/\\/g,"/"),r++;const o=Math.round(100*r/i);await e(a,t,r,i),s&&await s(t.path,r,i,o)}}finally{r.noAsar=!1}return i}static async extractArchive(t,e,{onProgress:s,removeRoot:r}={}){return this.processArchive(t,(async(t,s)=>{let a=s.path;r&&(a=a.replace(r,"")),a&&!a.endsWith("/")&&await this._extractEntry(t,e,s,a)}),s)}static async summarizeArchive(t,{manifestPath:e}={}){const s={contents:[],manifest:null};return await this.processArchive(t,(async(t,r)=>{const a=r.path;s.contents.push(a),a===e&&(s.manifest=await this._readEntry(t,r))})),s}static async _readEntry(t,e){return(await e.buffer()).toString()}static _extractEntry(t,e,s,r){const a=path.join(e,r);return fs.mkdirSync(path.dirname(a),{recursive:!0}),new Promise(((t,e)=>{s.stream().pipe(fs.createWriteStream(a)).on("error",e).on("finish",t)}))}static resolveClientPaths(t,e){return e.map((e=>{const s=path.join(e.root,e.directory),r=path.join(s,t),a=fs.existsSync(r);return this.isPathContained(r,s)?{exists:a,clientPath:LocalFileStorage.toClientPath(r,e.root)}:{exists:!1,clientPath:null}}))}static standardizePath(t){return path.normalize(t).split(path.sep).join(path.posix.sep)}static isPathContained(t,e){const s=path.relative(e,t);return!(s&&(s.startsWith("..")||path.isAbsolute(s)))}static writeFileSyncSafe(t,e,s={}){const r=`${t}~`,a=fs.openSync(r,"w");fs.writeFileSync(a,e,s),fs.fsyncSync(a),fs.closeSync(a),fs.renameSync(r,t);const i=fs.openSync(t,"r+");return fs.fsyncSync(i),fs.closeSync(i),i}static copyLargeFile(t,e,{encoding:s="utf8",mode:r=420}={}){return new Promise(((a,i)=>{const o=fs.createReadStream(t,{encoding:s}),n=fs.createWriteStream(e,{encoding:s,mode:r});o.on("error",i),n.on("error",i),n.on("finish",a),o