Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use async fs methods #11

Merged
merged 3 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,4 @@ dist
lib/
*.swp
*.swo
/temp
6 changes: 3 additions & 3 deletions src/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export class TrzszFilter {
if (items instanceof DataTransferItemList) {
this.uploadFilesList = await parseDataTransferItemList(items as DataTransferItemList);
} else if (isArrayOfType(items, "string") && !isRunningInBrowser) {
this.uploadFilesList = nodefs.checkPathsReadable(items as string[], true);
this.uploadFilesList = await nodefs.checkPathsReadable(items as string[], true);
} else {
throw new Error("The upload items type is not supported");
}
Expand Down Expand Up @@ -342,7 +342,7 @@ export class TrzszFilter {
await this.trzszTransfer.sendAction(false, remoteIsWindows);
return;
}
nodefs.checkPathWritable(savePath);
await nodefs.checkPathWritable(savePath);
saveParam = { path: savePath, maps: new Map<string, string>() };
openSaveFile = nodefs.openSaveFile;
}
Expand All @@ -368,7 +368,7 @@ export class TrzszFilter {
sendFiles = directory ? await browser.selectSendDirectories() : await browser.selectSendFiles();
} else {
const filePaths = await this.chooseSendFiles(directory);
sendFiles = nodefs.checkPathsReadable(filePaths, directory);
sendFiles = await nodefs.checkPathsReadable(filePaths, directory);
}

if (!sendFiles || !sendFiles.length) {
Expand Down
118 changes: 78 additions & 40 deletions src/nodefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

/* eslint-disable require-jsdoc */

const fs = requireSafely("fs");
const path = requireSafely("path");
import { TrzszError, TrzszFileReader, TrzszFileWriter } from "./comm";
Expand All @@ -18,20 +17,57 @@ function requireSafely(name) {
}
}

export function checkPathWritable(filePath: string) {
function promisify (fs: any, funcs: string[]) {
for (const func of funcs) {
fs[func + 'Async'] = (...args) => {
return new Promise((resolve, reject) => {
fs[func](...args, (err, data) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当有多个参数时,这里一个 data 参数不够吧?
https://nodejs.org/api/fs.html#fsreadfd-buffer-offset-length-position-callback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只有read的callback有多个返回,但是没有用到

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

多一个参数,就不需要这样一个一个地赋值了:
https://github.com/electerm/electerm/blob/e6c77eb94e865f511c4a6b9903cdbde09540e6ba/src/client/common/pre.js#L116-L118
可以直接返回另一个 buffer 。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zxdong262 我提交了一个 commit 在这个分支上 https://github.com/trzsz/trzsz.js/tree/electerm
( 没有权限直接提交到这个 PR 中来 )

if (err) {
return reject(err);
} else {
resolve(data || true);
}
})
})
}
}
}

promisify(
fs,
[
'stat',
'access',
'mkdir',
'readdir',
'read',
'close',
'open',
'realpath',
'write'
]
);

function fsExistsAsync (fp: string) {
return fs.accessAsync(fp)
.then(() => true)
.catch(() => false)
}

export async function checkPathWritable(filePath: string) {
if (!filePath) {
return false;
}

if (!fs.existsSync(filePath)) {
if (!await fsExistsAsync(filePath)) {
throw new TrzszError(`No such directory: ${filePath}`);
}
const stats = fs.statSync(filePath);
const stats = await fs.statAsync(filePath);
if (!stats.isDirectory()) {
throw new TrzszError(`Not a directory: ${filePath}`);
}
try {
fs.accessSync(filePath, fs.constants.W_OK);
await fs.accessAsync(filePath, fs.constants.W_OK);
} catch (err) {
throw new TrzszError(`No permission to write: ${filePath}`);
}
Expand Down Expand Up @@ -77,25 +113,25 @@ class NodefsFileReader implements TrzszFileReader {
throw new TrzszError(`File closed: ${this.absPath}`, null, true);
}
if (this.fd === null) {
this.fd = fs.openSync(this.absPath, "r");
this.fd = await fs.openAsync(this.absPath, "r");
}
const uint8 = new Uint8Array(buf);
const n = fs.readSync(this.fd, uint8, 0, uint8.length, null);
const n = await fs.readAsync(this.fd, uint8, 0, uint8.length, null);
return uint8.subarray(0, n);
}

public closeFile() {
public async closeFile() {
if (!this.closed) {
this.closed = true;
if (this.fd !== null) {
fs.closeSync(this.fd);
await fs.closeAsync(this.fd);
this.fd = null;
}
}
}
}

function checkPathReadable(
async function checkPathReadable(
pathId: number,
absPath: string,
stats: any,
Expand All @@ -108,46 +144,48 @@ function checkPathReadable(
throw new TrzszError(`Not a regular file: ${absPath}`);
}
try {
fs.accessSync(absPath, fs.constants.R_OK);
await fs.accessAsync(absPath, fs.constants.R_OK);
} catch (err) {
throw new TrzszError(`No permission to read: ${absPath}`);
}
fileList.push(new NodefsFileReader(pathId, absPath, relPath, false, stats.size));
return;
}

const realPath = fs.realpathSync(absPath);
const realPath = await fs.realpathAsync(absPath);
if (visitedDir.has(realPath)) {
throw new TrzszError(`Duplicate link: ${absPath}`);
}
visitedDir.add(realPath);
fileList.push(new NodefsFileReader(pathId, absPath, relPath, true, 0));

fs.readdirSync(absPath).forEach((file) => {
const arr = await fs.readdirAsync(absPath)
for (const file of arr) {
const filePath = path.join(absPath, file);
checkPathReadable(pathId, filePath, fs.statSync(filePath), fileList, [...relPath, file], visitedDir);
});
const stat = await fs.statAsync(filePath)
await checkPathReadable(pathId, filePath, stat, fileList, [...relPath, file], visitedDir);
}
}

export function checkPathsReadable(
export async function checkPathsReadable(
filePaths: string[] | undefined,
directory: boolean = false
): TrzszFileReader[] | undefined {
): Promise<TrzszFileReader[] | undefined> {
if (!filePaths || !filePaths.length) {
return undefined;
}
const fileList: NodefsFileReader[] = [];
for (const [idx, filePath] of filePaths.entries()) {
const entries = filePaths.entries()
for (const [idx, filePath] of entries) {
const absPath = path.resolve(filePath);
if (!fs.existsSync(absPath)) {
if (!await fsExistsAsync(absPath)) {
throw new TrzszError(`No such file: ${absPath}`);
}
const stats = fs.statSync(absPath);
const stats = await fs.statAsync(absPath);
if (!directory && stats.isDirectory()) {
throw new TrzszError(`Is a directory: ${absPath}`);
}
const visitedDir = new Set<string>();
checkPathReadable(idx, absPath, stats, fileList, [path.basename(absPath)], visitedDir);
await checkPathReadable(idx, absPath, stats, fileList, [path.basename(absPath)], visitedDir);
}
return fileList;
}
Expand Down Expand Up @@ -179,27 +217,27 @@ class NodefsFileWriter implements TrzszFileWriter {
}

public async writeFile(buf: Uint8Array) {
fs.writeSync(this.fd, buf);
await fs.writeAsync(this.fd, buf);
}

public closeFile() {
public async closeFile() {
if (!this.closed) {
this.closed = true;
if (this.fd !== null) {
fs.closeSync(this.fd);
await fs.closeAsync(this.fd);
this.fd = null;
}
}
}
}

function getNewName(savePath: string, fileName: string) {
if (!fs.existsSync(path.join(savePath, fileName))) {
async function getNewName(savePath: string, fileName: string) {
if (!fsExistsAsync(path.join(savePath, fileName))) {
return fileName;
}
for (let i = 0; i < 1000; i++) {
const saveName = `${fileName}.${i}`;
if (!fs.existsSync(path.join(savePath, saveName))) {
if (!await fsExistsAsync(path.join(savePath, saveName))) {
return saveName;
}
}
Expand All @@ -208,7 +246,7 @@ function getNewName(savePath: string, fileName: string) {

function doCreateFile(absPath: string) {
try {
return fs.openSync(absPath, "w");
return fs.openAsync(absPath, "w");
lonnywong marked this conversation as resolved.
Show resolved Hide resolved
} catch (err) {
if (err.errno === -13 || err.errno === -4048) {
throw new TrzszError(`No permission to write: ${absPath}`);
Expand All @@ -219,19 +257,19 @@ function doCreateFile(absPath: string) {
}
}

function doCreateDirectory(absPath: string) {
if (!fs.existsSync(absPath)) {
fs.mkdirSync(absPath, { recursive: true, mode: 0o755 });
async function doCreateDirectory(absPath: string) {
if (!await fsExistsAsync(absPath)) {
await fs.mkdirAsync(absPath, { recursive: true, mode: 0o755 });
}
const stats = fs.statSync(absPath);
const stats = await fs.statAsync(absPath);
if (!stats.isDirectory()) {
throw new TrzszError(`Not a directory: ${absPath}`);
}
}

function createFile(savePath, fileName: string, overwrite: boolean) {
const localName = overwrite ? fileName : getNewName(savePath, fileName);
const fd = doCreateFile(path.join(savePath, localName));
async function createFile(savePath, fileName: string, overwrite: boolean) {
const localName = overwrite ? fileName : await getNewName(savePath, fileName);
const fd = await doCreateFile(path.join(savePath, localName));
return new NodefsFileWriter(fileName, localName, fd);
}

Expand All @@ -258,25 +296,25 @@ export async function openSaveFile(saveParam: any, fileName: string, directory:
if (saveParam.maps.has(file.path_id)) {
localName = saveParam.maps.get(file.path_id);
} else {
localName = getNewName(saveParam.path, file.path_name[0]);
localName = await getNewName(saveParam.path, file.path_name[0]);
saveParam.maps.set(file.path_id, localName);
}
}

let fullPath: string;
if (file.path_name.length > 1) {
const p = path.join(saveParam.path, localName, ...file.path_name.slice(1, file.path_name.length - 1));
doCreateDirectory(p);
await doCreateDirectory(p);
fullPath = path.join(p, fileName);
} else {
fullPath = path.join(saveParam.path, localName);
}

if (file.is_dir === true) {
doCreateDirectory(fullPath);
await doCreateDirectory(fullPath);
return new NodefsFileWriter(fileName, localName, null, true);
}

const fd = doCreateFile(fullPath);
const fd = await doCreateFile(fullPath);
return new NodefsFileWriter(fileName, localName, fd);
}
2 changes: 1 addition & 1 deletion src/trz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ async function main() {

try {
args.path = path.resolve(args.path);
nodefs.checkPathWritable(args.path);
await nodefs.checkPathWritable(args.path);

const [tmuxMode, realStdoutWriter, tmuxPaneWidth] = await checkTmux();

Expand Down
2 changes: 1 addition & 1 deletion src/tsz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ async function main() {
const args = parseArgs();

try {
const fileList = checkPathsReadable(args.file, args.directory);
const fileList = await checkPathsReadable(args.file, args.directory);
if (!fileList) {
return;
}
Expand Down
Loading