mirror of
https://github.com/TheodoreKrypton/tgfs
synced 2024-11-22 23:32:45 +00:00
add ls command
This commit is contained in:
parent
c73760f02b
commit
624f10f90b
@ -9,6 +9,8 @@
|
||||
"start": "yarn build:dev && node dist/src/index.js",
|
||||
"start:dev": "yarn build:dev && nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts",
|
||||
"start:prod": "yarn build && node dist/src/index.js",
|
||||
"start:cmd": "yarn build:dev && node dist/src/cmd.js",
|
||||
"start:cmd:prod": "yarn build && node dist/src/cmd.js",
|
||||
"test": "yarn jest"
|
||||
},
|
||||
"author": "Wheat Carrier",
|
||||
|
@ -15,13 +15,17 @@ export class Client {
|
||||
metadata: TGFSMetadata;
|
||||
|
||||
constructor(
|
||||
public readonly client: TelegramClient,
|
||||
protected readonly client: TelegramClient,
|
||||
private readonly privateChannelId: string,
|
||||
private readonly publicChannelId?: string,
|
||||
) {}
|
||||
|
||||
public async init() {
|
||||
this.metadata = await this.getMetadata();
|
||||
if (!this.metadata) {
|
||||
this.metadata = new TGFSMetadata();
|
||||
await this.createEmptyDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
private async send(message: string) {
|
||||
@ -42,6 +46,11 @@ export class Client {
|
||||
);
|
||||
}
|
||||
|
||||
public async getFileInfo(fileRef: TGFSFileRef): Promise<TGFSFile> {
|
||||
const file = await this.getFileFromFileRef(fileRef);
|
||||
return file;
|
||||
}
|
||||
|
||||
private async downloadMediaById(
|
||||
messageIds: number,
|
||||
downloadParams?: DownloadMediaInterface,
|
||||
@ -88,8 +97,7 @@ export class Client {
|
||||
)[0];
|
||||
|
||||
if (!pinnedMessage) {
|
||||
await this.createEmptyDirectory();
|
||||
return this.metadata;
|
||||
return null;
|
||||
}
|
||||
|
||||
const metadata = TGFSMetadata.fromObject(
|
||||
@ -114,16 +122,24 @@ export class Client {
|
||||
|
||||
private async updateMetadata() {
|
||||
const buffer = Buffer.from(JSON.stringify(this.metadata.toObject()));
|
||||
return await this.client.editMessage(this.privateChannelId, {
|
||||
message: this.metadata.msgId,
|
||||
file: new CustomFile('metadata.json', buffer.length, '', buffer),
|
||||
});
|
||||
const file = new CustomFile('metadata.json', buffer.length, '', buffer);
|
||||
if (this.metadata.msgId) {
|
||||
return await this.client.editMessage(this.privateChannelId, {
|
||||
message: this.metadata.msgId,
|
||||
file,
|
||||
});
|
||||
} else {
|
||||
const message = await this.client.sendMessage(this.privateChannelId, {
|
||||
file,
|
||||
});
|
||||
this.metadata.msgId = message.id;
|
||||
await this.client.pinMessage(this.privateChannelId, message.id);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
public async createEmptyDirectory() {
|
||||
this.metadata = new TGFSMetadata();
|
||||
this.metadata.dir = new TGFSDirectory('root', null, []);
|
||||
|
||||
await this.syncMetadata();
|
||||
|
||||
return this.metadata.dir;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as input from 'input';
|
||||
import { Logger } from 'src/utils/logger';
|
||||
|
||||
import { Logger } from '../utils/logger';
|
||||
import { login } from './login';
|
||||
|
||||
export const loginAsUser = login(async (client) => {
|
||||
|
2
src/auth/index.ts
Normal file
2
src/auth/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { loginAsBot } from './as-bot';
|
||||
export { loginAsUser } from './as-user';
|
42
src/cmd.ts
Normal file
42
src/cmd.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import yargs from 'yargs/yargs';
|
||||
|
||||
import { loginAsBot } from './auth';
|
||||
import { Executor } from './commands/executor';
|
||||
|
||||
const parse = () => {
|
||||
const argv: any = yargs(hideBin(process.argv))
|
||||
.command('ls <path>', 'list all files and directories', {
|
||||
path: {
|
||||
type: 'string',
|
||||
description: 'path to list',
|
||||
},
|
||||
})
|
||||
.command('mkdir <path>', 'create a directory', {
|
||||
path: {
|
||||
type: 'string',
|
||||
description: 'path to create',
|
||||
},
|
||||
})
|
||||
.demandCommand(1, 'You need at least one command before moving on')
|
||||
.help().argv;
|
||||
|
||||
return argv;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const client = await loginAsBot();
|
||||
|
||||
await client.init();
|
||||
|
||||
const executor = new Executor(client);
|
||||
|
||||
const argv = parse();
|
||||
await executor.execute(argv);
|
||||
} catch (err) {
|
||||
console.log(err.message);
|
||||
} finally {
|
||||
process.exit(0);
|
||||
}
|
||||
})();
|
20
src/commands/executor.ts
Normal file
20
src/commands/executor.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Client } from '../api';
|
||||
import { ls } from './ls';
|
||||
import { mkdir } from './mkdir';
|
||||
|
||||
export class Executor {
|
||||
constructor(private readonly client: Client) {}
|
||||
|
||||
async execute(argv: any) {
|
||||
let rsp: any;
|
||||
|
||||
if (argv._[0] === 'ls') {
|
||||
rsp = await ls(this.client)(argv.path);
|
||||
} else if (argv._[0] === 'mkdir') {
|
||||
rsp = await mkdir(this.client)(argv.path);
|
||||
} else if (argv._[0] === '') {
|
||||
}
|
||||
|
||||
console.log(rsp);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export function get(messageId: string) {
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import yargs from 'yargs/yargs';
|
||||
|
||||
import { ls } from './ls';
|
||||
|
||||
const argv: any = yargs(hideBin(process.argv))
|
||||
.command('ls', 'list all files', (yargs) => {
|
||||
return yargs.option('path', {
|
||||
describe: 'Path to list files from',
|
||||
demandOption: true,
|
||||
type: 'string',
|
||||
});
|
||||
})
|
||||
.demandCommand(1, 'You need at least one command before moving on')
|
||||
.help().argv;
|
||||
|
||||
if (argv._[0] === 'ls') {
|
||||
ls(argv.path);
|
||||
} else if (argv._[0] === 'get') {
|
||||
} else if (argv._[0] === 'send') {
|
||||
}
|
@ -1,5 +1,44 @@
|
||||
import { PathLike } from 'fs';
|
||||
|
||||
export const ls = (path: PathLike) => {
|
||||
console.log(path);
|
||||
import { Client } from '../api';
|
||||
import { FileOrDirectoryDoesNotExistError } from '../errors/directory';
|
||||
import { TGFSFileRef } from '../model/directory';
|
||||
import { navigateToDir } from './navigate-to-dir';
|
||||
|
||||
const fileInfo = async (client: Client, fileRef: TGFSFileRef) => {
|
||||
const info = await client.getFileInfo(fileRef);
|
||||
const head = `${info.name}, ${Object.keys(info.versions).length} versions`;
|
||||
const versions = Object.entries(info.versions).map(([id, version]) => {
|
||||
return `${id}: updated at ${version.updatedAt}`;
|
||||
});
|
||||
return [head, ...versions].join('\n');
|
||||
};
|
||||
|
||||
export const ls = (client: Client) => async (path: PathLike) => {
|
||||
const parts = path
|
||||
.toString()
|
||||
.split('/')
|
||||
.filter((part) => part !== '');
|
||||
let dir = await navigateToDir(client)(
|
||||
parts.slice(0, parts.length - 1).join('/'),
|
||||
);
|
||||
|
||||
let nextDir = dir;
|
||||
|
||||
if (parts.length > 0) {
|
||||
nextDir = dir.children.find((d) => d.name === parts[parts.length - 1]);
|
||||
}
|
||||
if (nextDir) {
|
||||
return nextDir.children
|
||||
.map((c) => c.name)
|
||||
.concat(dir.files?.map((f) => f.name))
|
||||
.join(' ');
|
||||
} else {
|
||||
const nextFile = dir.files?.find((f) => f.name === parts[parts.length - 1]);
|
||||
if (nextFile) {
|
||||
return fileInfo(client, nextFile);
|
||||
} else {
|
||||
throw new FileOrDirectoryDoesNotExistError(path.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
13
src/commands/mkdir.ts
Normal file
13
src/commands/mkdir.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Client } from '../api';
|
||||
import { navigateToDir } from './navigate-to-dir';
|
||||
|
||||
export const mkdir = (client: Client) => async (path: string) => {
|
||||
const parts = path.toString().split('/');
|
||||
const dir = await navigateToDir(client)(
|
||||
parts.slice(0, parts.length - 1).join('/'),
|
||||
);
|
||||
|
||||
await client.createDirectoryUnder(parts[parts.length - 1], dir);
|
||||
|
||||
return `created ${path}`;
|
||||
};
|
27
src/commands/navigate-to-dir.ts
Normal file
27
src/commands/navigate-to-dir.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { TGFSDirectory } from 'src/model/directory';
|
||||
|
||||
import { Client } from '../api';
|
||||
import { FileOrDirectoryDoesNotExistError } from '../errors/directory';
|
||||
|
||||
export const navigateToDir = (client: Client) => async (path: string) => {
|
||||
const pathParts = path
|
||||
.toString()
|
||||
.split('/')
|
||||
.filter((part) => part !== '');
|
||||
|
||||
let currentDirectory = client.metadata.dir;
|
||||
|
||||
for (const pathPart of pathParts) {
|
||||
const directory = currentDirectory.children?.find(
|
||||
(d: TGFSDirectory) => d.name === pathPart,
|
||||
);
|
||||
|
||||
if (!directory) {
|
||||
throw new FileOrDirectoryDoesNotExistError(path);
|
||||
}
|
||||
|
||||
currentDirectory = directory;
|
||||
}
|
||||
|
||||
return currentDirectory;
|
||||
};
|
@ -1,10 +1,16 @@
|
||||
import { BusinessError } from './base';
|
||||
|
||||
export class DirectoryAlreadyExistsError extends BusinessError {
|
||||
constructor(public readonly dirName: string, public readonly cause?: string) {
|
||||
super(`Directory ${dirName} already exists`, 'DIR_ALREADY_EXISTS', cause);
|
||||
}
|
||||
}
|
||||
|
||||
export class FileOrDirectoryDoesNotExistError extends BusinessError {
|
||||
constructor(public readonly dirName: string, public readonly cause?: string) {
|
||||
super(
|
||||
`Directory ${dirName} already exists`,
|
||||
'DIRECTORY_ALREADY_EXISTS',
|
||||
`No such file or directory: ${dirName}`,
|
||||
'FILE_OR_DIR_DOES_NOT_EXIST',
|
||||
cause,
|
||||
);
|
||||
}
|
||||
|
@ -2,5 +2,6 @@ export type ErrorCodes =
|
||||
| 'UNKNOWN'
|
||||
| 'EMPTY_FILE'
|
||||
| 'FILE_IS_EMPTY'
|
||||
| 'DIRECTORY_ALREADY_EXISTS'
|
||||
| 'FILE_ALREADY_EXISTS';
|
||||
| 'DIR_ALREADY_EXISTS'
|
||||
| 'FILE_ALREADY_EXISTS'
|
||||
| 'FILE_OR_DIR_DOES_NOT_EXIST';
|
||||
|
Loading…
Reference in New Issue
Block a user