import { VirtualFS, type TreeNode } from './fs'; import { Terminal, type PrintData } from '../terminal/terminal'; import { Stack } from '../stack'; import { PASSWD, type User } from './etc/userData'; import { ExitCode } from './metadata'; import { COMMANDS, type CommandArgs, type CommandResultData, type ICommand } from './commandRegistry'; import { GROUP, type Group } from './etc/groupData'; export type BashInitArgs = { io?: Terminal; instanceId: number; user: {username: string, password: string}; fs?: VirtualFS; }; export type Result = { exitCode: ExitCode; path: number; //the inode of the place that the command was executed in resultData?: CommandResultData; }; export class Bash { private readonly _instanceId: number; private vfs: VirtualFS; private _passwd: User[]; private _userInstances: Stack; private _group: Group[]; private _terminal!: Terminal; private user: User; private readonly _commands: Record; constructor(args: BashInitArgs) { this._instanceId = args.instanceId this._commands = COMMANDS; this._passwd = PASSWD; this._group = GROUP; this._userInstances = new Stack(); this._terminal = args.io!; const loginResult = this.userLogin(args.user.username, args.user.password); if(loginResult == ExitCode.ERROR) this._terminal.throwExeption( `Failed to initialize bash instance - access denied for user ${args.user.username}`, ExitCode.ERROR ) this.user = this._userInstances.peek()! this.vfs = this._terminal.fileSystem; } private _initNewUserSession(user: User): User { if(!this._passwd.includes(user)) this._terminal.throwExeption(`user not found under the name ${user.username}`, ExitCode.ERROR) this._userInstances.push(user); return user } private _appendNewResult(inode: number, output: any, cmd: string) { const data: PrintData = { path: this.vfs.formatPath(this.vfs.getPathByInode(inode)), output: output, cmd: cmd }; console.log(data); this._terminal.PrintOutput(data); } updateHistory(input: string): void { if ((this.user.history.length = 255)) { this.user.history.unshift(...this.user.history.splice(-1)); this.user.history[0] = input; } else { this.user.history.push(input); this.user.history.unshift(...this.user.history.splice(-1)); } } clearTerminal(): void { this._terminal.clearTerminal(); } getCwd(): number { return this.vfs.cwd; } getPwd(): number { return this.vfs.pwd; } getUser(): User { return this.user; } getFs(): VirtualFS { return this.vfs; } getTerminalWidth(): number { return this._terminal.getTerminalWidth(); } getTerminalFontSize(): number { return this._terminal.getFontSize(); } hasSudoPerms(uid: number): boolean { return this._group[1].members.includes(uid); } async executeCommand(commandName: string, args: CommandArgs) { let result: Result = { exitCode: ExitCode.ERROR, path: this.getCwd() }; const command = this._commands[commandName]; if (!command) this.throwError(result); if (command.root) { if (this.hasSudoPerms(this.user.uid)) { let out: Result = command.method.call(this, args); this._appendNewResult(this.getCwd(), out, this.user.history[0]); } this.throwError(result); } let out: Result = command.method.call(this, args); console.log(out); this._appendNewResult(out.path, out.resultData?.data, this.user.history[0]); } throwError(result: Result): void { switch (result.exitCode) { default: { throw new Error(`Error, dont know where, just look for it;`); } } } userLogout() { this._userInstances.pop(); if (this._userInstances.size() === 0) { //TODO: Implement system logout } else { //this.changeUser(this._instances.peek()!); } } userLogin(username: string, passwd: string): ExitCode { const user: User | undefined = this._passwd.find((user) => user.username === username); if(user && user.passwd === passwd) { this._initNewUserSession(user); return ExitCode.SUCCESS; } return ExitCode.ERROR; } formatBytes(bytes: number, dPoint?: number, pow: 1024 | 1000 = 1024): string { if (!+bytes) return '0'; const k: number = pow; const dp: number = dPoint ? (dPoint < 0 ? 0 : dPoint) : 1; const units: string[] = ['', 'K', 'M', 'G', 'T', 'P']; const i: number = Math.floor(Math.log(bytes) / Math.log(k)); return `${(bytes / Math.pow(k, i)).toFixed(dp)}${units[i]}`; } getGroupByName(name: string): Group { const out: Group | undefined = this._group.find((group) => group.groupname === name); if (out) return out; else throw new Error(`Cannot find a user group named ${name}`); } getUserByName(name: string): User { const out: User | undefined = this._passwd.find((user) => user.username === name); if (out) return out; else throw new Error(`Cannot find a user named ${name}`); } getGroupByGid(gid: number): Group { const out: Group | undefined = this._group.find((group) => group.gid === gid); if (out) return out; else throw new Error(`Cannot find a user group with id of ${gid}`); } getUserByUid(uid: number): User { const out: User | undefined = this._passwd.find((user) => user.uid === uid); if (out) return out; else throw new Error(`Cannot find a user with id of ${uid}`); } }