Skip to content
19 changes: 19 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "node-nodejs-basics",
"version": "1.0.0",
"description": "This repository is the part of nodejs-assignments https://github.com/AlreadyBored/nodejs-assignments",
"type": "module",
"scripts": {
"start": "node src/file_manager.js",
"test": "node src/file_manager.js -- --username=docroot"
},
"repository": {
"type": "git",
"url": "git+https://github.com/docroot/nodejs_file_manager.git"
},
"author": "docroot",
"bugs": {
"url": "https://github.com/docroot/nodejs_file_manager/issues"
},
"homepage": "https://github.com/docroot/nodejs_file_manager.git#readme"
}
19 changes: 19 additions & 0 deletions src/commands/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import fs from 'fs/promises';
import path from 'path';

const cmd_add = async (ctx, args) => {
if (args.length !== 1) throw new Error();
let filePath;
if (path.isAbsolute(args[0])) {
filePath = args[0];
}
else {
filePath = path.join(ctx.cwd, args[0]);
}

await fs.writeFile(filePath, '', { flag: 'wx' });
}

export {
cmd_add
}
93 changes: 93 additions & 0 deletions src/commands/arch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { error } from 'console';
import fs, { lstat } from 'fs';
import path from 'path';
import zlib from 'zlib';

const cmd_compress = async (ctx, args) => {
if (args.length !== 1) throw new Error();
let filePath;
if (path.isAbsolute(args[0])) {
filePath = args[0];
}
else {
filePath = path.join(ctx.cwd, args[0]);
}

const archPath = filePath + '.br';

const inputStream = fs.createReadStream(filePath);
const writeStream = fs.createWriteStream(archPath, { flags: 'wx' });

const brotliOptions = {
chunkSize: 64 * 1024,
params: {
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_GENERIC,
[zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_MAX_QUALITY,
},
};
const brotliStream = zlib.createBrotliCompress(brotliOptions);

await new Promise((resolve, reject) => {
inputStream.on('error', (error) => {
reject(error);
})
brotliStream.on('error', (error) => {
reject(error);
})
writeStream.on('error', (error) => {
reject(error);
});
writeStream.on('finish', () => {
resolve();
});
inputStream.pipe(brotliStream).pipe(writeStream);
}
).catch((error) => { throw error; });
}

const cmd_decompress = async (ctx, args) => {
if (args.length !== 1) throw new Error();
let archPath;
if (path.isAbsolute(args[0])) {
archPath = args[0];
}
else {
archPath = path.join(ctx.cwd, args[0]);
}

const re = /\.br$/;
let filePath = archPath;
if (re.test(filePath)) {
filePath = filePath.slice(0, -3);
}
else {
filePath = filePath + '.unpkd';
}

const inputStream = fs.createReadStream(archPath);
const writeStream = fs.createWriteStream(filePath, { flags: 'wx' });

const brotliStream = zlib.createBrotliDecompress();

await new Promise((resolve, reject) => {
inputStream.on('error', (error) => {
reject(error);
})
brotliStream.on('error', (error) => {
reject(error);
})
writeStream.on('error', (error) => {
reject(error);
});
writeStream.on('finish', () => {
resolve();
});
inputStream.pipe(brotliStream).pipe(writeStream);
}
).catch((error) => { throw error; });
}

export {
cmd_compress,
cmd_decompress
}
30 changes: 30 additions & 0 deletions src/commands/cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import fs from 'fs';
import path from 'path';

const cmd_cat = async (ctx, args) => {
if (args.length !== 1) throw new Error();
let filePath;
if (path.isAbsolute(args[0])) {
filePath = args[0];
}
else {
filePath = path.join(ctx.cwd, args[0]);
}

await new Promise((resolve, reject) => {
const inputStream = fs.createReadStream(filePath, 'utf8');
inputStream.pipe(process.stdout);
inputStream.on('end', () => {
inputStream.close();
resolve();
})
inputStream.on('error', (error) => {
reject(error);
})
}
).catch((error) => { throw error; });
}

export {
cmd_cat
}
18 changes: 18 additions & 0 deletions src/commands/cd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import path from 'path';

const cmd_cd = (ctx, args) => {
if (args.length > 1) throw new Error();
let newDir;
if (path.isAbsolute(args[0])) {
newDir = args[0];
}
else {
newDir = path.join(ctx.cwd, args[0]);
}
process.chdir(newDir);
ctx.cwd = process.cwd();
}

export {
cmd_cd
}
45 changes: 45 additions & 0 deletions src/commands/cp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import fs from 'fs';
import path from 'path';

const cmd_cp = async (ctx, args) => {
if (args.length !== 2) throw new Error();
let filePaths = [];
const fileName = path.basename(args[0]);

if (path.isAbsolute(args[0])) {
filePaths.push(args[0]);
}
else {
filePaths.push(path.join(ctx.cwd, args[0]));
}

if (path.isAbsolute(args[1])) {
filePaths.push(path.join(args[1], fileName));
}
else {
filePaths.push(path.join(ctx.cwd, args[1], fileName));
}

const srcStream = fs.createReadStream(filePaths[0], { flags: 'r' });
const dstStream = fs.createWriteStream(filePaths[1], { flags: 'wx' });

await new Promise((resolve, reject) => {
dstStream.on('finish', () => {
dstStream.close();
srcStream.close();
resolve();
});
srcStream.on('error', (error) => {
reject(error);
});
dstStream.on('error', (error) => {
reject(error);
});
srcStream.pipe(dstStream);
}
).catch((error) => { srcStream.close(); dstStream.close(); throw error; });
}

export {
cmd_cp
}
7 changes: 7 additions & 0 deletions src/commands/exit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const cmd_exit = (ctx, args) => {
process.exit(0);
}

export {
cmd_exit
}
37 changes: 37 additions & 0 deletions src/commands/hash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import fs from 'fs';
import path from 'path';
import crypto from 'crypto';

const cmd_hash = async (ctx, args) => {
if (args.length !== 1) throw new Error();
let filePath;
if (path.isAbsolute(args[0])) {
filePath = args[0];
}
else {
filePath = path.join(ctx.cwd, args[0]);
}

const hash = crypto.createHash('sha256');
const inputStream = fs.createReadStream(filePath);

await new Promise((resolve, reject) => {
inputStream.on('end', () => {
inputStream.close();
})
inputStream.on('error', (error) => {
reject(error);
})
hash.on('finish', () => {
resolve();
});
inputStream.pipe(hash);
}
).catch((error) => { throw error; });

console.log(hash.digest('hex'));
}

export {
cmd_hash
}
44 changes: 44 additions & 0 deletions src/commands/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import fs from 'fs/promises';
import path from 'path';

const cmd_ls = async (ctx, args) => {
if (args.length > 1) throw new Error();
let dir = ctx.cwd;
if (args.length === 1) {
if (path.isAbsolute(args[0])) {
dir = args[0];
}
else {
dir = path.join(ctx.cwd, args[0]);
}
}
try {
const files = await fs.readdir(dir);
const filesInfo = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const filePath = path.join(dir, file);
try {
const fileStats = await fs.stat(filePath);
filesInfo.push({ 'Name': file, 'Type': (fileStats.isDirectory() ? 'DIR' : 'File'), 'size': fileStats.size, });
} catch (error) {
}
}
filesInfo.sort((a, b) => {
if (a.Type === b.Type) {
return a.Name.localeCompare(b.Name);
}
if (a.Type === 'DIR') {
return -1;
}
return 1;
});
console.table(filesInfo);
} catch (error) {
throw error;
}
}

export {
cmd_ls
}
12 changes: 12 additions & 0 deletions src/commands/mv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { cmd_cp } from './cp.js';
import { cmd_rm } from './rm.js';

const cmd_mv = async (ctx, args) => {
if (args.length !== 2) throw new Error();
await cmd_cp(ctx, args);
await cmd_rm(ctx, [args[0]]);
}

export {
cmd_mv
}
43 changes: 43 additions & 0 deletions src/commands/os.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import os from 'os';

const cmd_os = async (ctx, args) => {
if (args.length !== 1) throw new Error();

const re = /^--.+/;
if (!re.test(args[0])) throw new Error();

const opt = args[0].substring(2);

switch (opt) {
case 'EOL':
const eol = JSON.stringify(os.EOL);
console.log(`Default system End-Of-Line is \x1b[1m\x1b[32m${eol}\x1b[0m`);
break;
case 'cpus':
const cpus = os.cpus();
console.log(`Number of CPUs is [\x1b[1m\x1b[32m${cpus.length}\x1b[0m]`);
const cpuInfo = [];
cpus.forEach(cpu => {
cpuInfo.push({ 'Model': cpu.model, 'Clock rate (GHz)': (cpu.speed / 1000).toFixed(2) });
});
console.table(cpuInfo);
break;
case 'homedir':
console.log(`The HOMEDIR is [\x1b[1m\x1b[32m${ctx.homedir}\x1b[0m]`);
break;
case 'username':
const username = os.userInfo().username;
console.log(`The USERNAME is [\x1b[1m\x1b[32m${username}\x1b[0m]`);
break;
case 'architecture':
console.log(`The ARCHITECTURE is [\x1b[1m\x1b[32m${process.arch}\x1b[0m]`);
break;

default:
throw new Error();
}
}

export {
cmd_os
}
Loading