Files
upstream-rocketchat/apps/meteor/server/ufs/ufs-local.ts
upstream-mirror 30810eecd7
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:21:02 +05:00

112 lines
3.0 KiB
TypeScript

import fs from 'node:fs';
import { unlink } from 'node:fs/promises';
import { isNativeError } from 'node:util/types';
import type { IUpload } from '@rocket.chat/core-typings';
import mkdirp from 'mkdirp';
import { UploadFS } from './ufs';
import type { StoreOptions } from './ufs-store';
import { Store } from './ufs-store';
type LocalStoreOptions = StoreOptions & {
mode?: string;
path?: string;
writeMode?: number;
};
export class LocalStore extends Store {
protected getPath: (file: string) => string;
constructor(options: LocalStoreOptions) {
// Default options
options = {
mode: '0744',
path: 'ufs/uploads',
writeMode: 0o744,
...options,
};
// Check options
if (typeof options.mode !== 'string') {
throw new TypeError('LocalStore: mode is not a string');
}
if (typeof options.path !== 'string') {
throw new TypeError('LocalStore: path is not a string');
}
if (typeof options.writeMode !== 'number') {
throw new TypeError('LocalStore: writeMode is not a string');
}
super(options);
// Private attributes
const { mode } = options;
const { path } = options;
const { writeMode } = options;
fs.stat(path, (err) => {
if (err) {
// Create the directory
mkdirp(path, { mode })
.then(() => {
console.info(`LocalStore: store created at ${path}`);
})
.catch((err) => {
console.error(`LocalStore: cannot create store at ${path} (${err.message})`);
});
} else {
// Set directory permissions
fs.chmod(path, mode, (err) => {
err && console.error(`LocalStore: cannot set store permissions ${mode} (${err.message})`);
});
}
});
this.getPath = function (file) {
return path + (file ? `/${file}` : '');
};
this.delete = async (fileId, options) => {
const path = await this.getFilePath(fileId);
try {
await unlink(path);
} catch (error) {
if (!isNativeError(error) || !('code' in error) || !(error.code === 'ENOENT')) {
throw error;
}
}
await this.removeById(fileId, { session: options?.session }, true);
};
this.getReadStream = async (fileId: string, file: IUpload, options?: { start?: number; end?: number }) => {
options = Object.assign({}, options);
return fs.createReadStream(await this.getFilePath(fileId, file), {
flags: 'r',
encoding: undefined,
autoClose: true,
start: options.start,
end: options.end,
});
};
this.getWriteStream = async (fileId: string, file: IUpload, options?: { start?: number }) => {
options = Object.assign({}, options);
return fs.createWriteStream(await this.getFilePath(fileId, file), {
flags: 'a',
encoding: undefined,
mode: writeMode,
start: options.start,
});
};
}
override async getFilePath(fileId: string, fileParam?: IUpload): Promise<string> {
const file = fileParam || (await this.getCollection().findOne(fileId, { projection: { extension: 1 } }));
return (file && this.getPath(fileId + (file.extension ? `.${file.extension}` : ''))) || '';
}
}
// Add store to UFS namespace
UploadFS.store.Local = LocalStore;