var term = new Terminal({ cursorStyle: "underline", cols: 180, rows: 50 }); term.open(document.querySelector('#terminal')); function newLine(t = true, prompt = true) { t && term.write('\r\n'); cursorPosition = 0; if(prompt) { term.write(DEFAULT_PROMPT); cursorPosition += CLEAR_STYLING(DEFAULT_PROMPT).length; } resetUserSpace() } let waitms = ms => new Promise(ok => setTimeout(()=>ok(), ms)); let cursorPosition = 0; let _buffer = []; let COLOR_RESET = () => "\x1B[0m"; let COLOR_TEXT = (r,g,b) => `\x1B[38;2;${r};${g};${b}m`; let COLOR_BACKGROUND = (r,g,b) => `\x1B[48;2;${r};${g};${b}m`; let CURSOR_MOVE = (row, col) => `\x1B[${row};${col}H`; let CURSOR_MOVE_UP = () => `\x1B[A`; let CURSOR_MOVE_DOWN = () => `\x1B[B`; let CURSOR_MOVE_RIGHT = () => `\x1B[C`; let CURSOR_MOVE_LEFT = () => `\x1B[D`; let CLEAR_SCREEN = () => `\x1B[2J`; let CLEAR_LINE = () => `\x1B[2K`; term.write(CURSOR_MOVE(2,1)); let CLEAR_STYLING = (text) => text.toString().replace(/\x1B(.*?)m/ig,''); function writeHi() { term.write( "Merhaba, " + COLOR_TEXT(0,255,0) + COLOR_BACKGROUND(32,32,32) + ' saQut RC Shell ' + COLOR_RESET() + "\n\n\r" ); newLine(); } let userSpace = { buffer: [], paddingChars: 0, size: 0 }; function resetUserSpace() { userSpace = { buffer: [], paddingChars: 0, size: 0 } } function getCurrentLine() { return term .buffer .active .getLine( term .buffer .active .cursorY ) .translateToString() } let pausedInput = false; let activeProgram = false; term.onData(async chars => { if(pausedInput) { return } if(chars.length > 1) { return await DefaultProcess(chars); } if(chars.length == 1) { if(activeProgram) { if(activeProgram._sys.idleChar) { return activeProgram._sys.idleChar.triggerChar(chars); } } return await DefaultProcess(chars); }else if(activeProgram){ return } let tokens = []; chars.toString().replace(/(\x1B.+?m)|(\x1B\[.+)|(.+)/igm, (_,a,b,c,d,e,f,g) => { let charx = a || b || c; if(charx) { if(/^(\x1B.*?m)$|^(\x1B\[.*)$/i.test(charx)) { tokens.push([charx,]) }else{ tokens.push([,charx]) } } }); for (const [code, chars] of tokens) { pausedInput = true; if(code) { await DefaultProcess(code); }else if(chars) { for (const char of chars.split('')) { await DefaultProcess(char); } } pausedInput = false; } }) async function DefaultProcess(char) { let contextchanged = false; switch(char) { // Backspace case '\x7f': if(userSpace.paddingChars > 0) { term.write('\b \b'); cursorPosition--; let after = userSpace.buffer.slice(0, userSpace.paddingChars - 1); let before = userSpace.buffer.slice(userSpace.paddingChars); userSpace.buffer = [ ...after, ...before ]; userSpace.paddingChars--; userSpace.size--; contextchanged = true; term.write(before.join('')+" \b"); term.write(before.map(() => '\b').join('')); } break; // Enter case '\r': let command = userSpace.buffer.join(''); if(activeProgram && activeProgram._sys.idleReadline) { newLine(true, false); return activeProgram._sys.triggerReadline(command); } let parsedCommand = ParseCommand(command); if(parsedCommand != false) { let program = parsedCommand.find(e => e.type == 'commandname').data; pausedInput = true; newLine(true, false); await ExecuteCommand( program, parsedCommand ); pausedInput = false; newLine(false); }else{ newLine(); } break; case CURSOR_MOVE_LEFT(): if(userSpace.paddingChars > 0) { userSpace.paddingChars--; term.write(CURSOR_MOVE_LEFT()); } break; case CURSOR_MOVE_UP(): case CURSOR_MOVE_DOWN(): break; // Delete case "\x1B[3~": let after = userSpace.buffer.slice(0, userSpace.paddingChars); let before = userSpace.buffer.slice(userSpace.paddingChars + 1); term.write(before.join('')+" \b"); term.write(before.map(() => '\b').join('')); userSpace.buffer = [ ...after, ...before ]; userSpace.size--; contextchanged = true; break; case CURSOR_MOVE_RIGHT(): if(userSpace.paddingChars < userSpace.size) { term.write(CURSOR_MOVE_RIGHT()); userSpace.paddingChars++; } break; default: let printable = char.charCodeAt(0); if(printable < 32) { return } // insert or append ? if(userSpace.paddingChars == userSpace.size) { term.write(char); userSpace.buffer = [ ...userSpace.buffer.slice(0, userSpace.paddingChars), char, ...userSpace.buffer.slice(userSpace.paddingChars), ]; userSpace.paddingChars++; userSpace.size++; cursorPosition++; contextchanged = true; }else{ let after = userSpace.buffer.slice(0, userSpace.paddingChars); let before = userSpace.buffer.slice(userSpace.paddingChars); userSpace.buffer = [ ...after, char, ...before ]; term.write(char); term.write(before.join('')); term.write(before.map(() => '\b').join('')); contextchanged = true; userSpace.paddingChars++; userSpace.size++; cursorPosition++; } } if(!activeProgram) { contextchanged && COLORIZE_LINE(); } }; async function COLORIZE_LINE() { let before = userSpace.buffer.slice(0, userSpace.paddingChars); let after = userSpace.buffer.slice(userSpace.paddingChars); let coloredCommand = CommandColorize(before.concat(after).join('')); if(coloredCommand) { // Cursoru en başa al term.write(CURSOR_MOVE_LEFT().repeat(before.length)); term.write(coloredCommand); term.write(CURSOR_MOVE_LEFT().repeat(after.length)); } } let USER_SPACE = "virtualhost"; let USER_NAME = [ 147 + Math.random() * 25 | 0, 200 + Math.random() * 56 | 0, 0 + Math.random() * 256 | 0, 0 + Math.random() * 256 | 0 ].join('.'); let DEFAULT_PROMPT = ( COLOR_RESET() + '[' + COLOR_TEXT(0,255,0) + USER_SPACE + ' ' + COLOR_TEXT(0,128,255) + USER_NAME + COLOR_RESET() + '] $ ' ); writeHi(); let _color_command = [255,255,255]; let _color_option = [128,128,255]; let _color_stringdata = [128,255,64]; function CommandColorize(command) { let hmx = new Hemex(); hmx.setText(command); let output = []; let commandBefore = hmx.of(() => !hmx.isLetter()); if(commandBefore.length != 0) { output.push( COLOR_TEXT(255,255,255), commandBefore, COLOR_RESET() ) } if(!hmx.isLetter()) { return false } let commandName = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$'])); if(hmx.isEnd() && !hmx.isWhiteSpace()) { return false } output.push( COLOR_TEXT(..._color_command), commandName, COLOR_RESET() ); let all = [], stringstarted = false; hmx.each(() => { let char = hmx.getChar(); switch(char) { case '\'': case '"': case '`':{ if(stringstarted == false) { stringstarted = char; all.push(COLOR_TEXT(..._color_stringdata), char) }else if(stringstarted == char){ stringstarted = false; all.push(char, COLOR_TEXT(..._color_option)) }else{ all.push(char) } return true; } default:{ if(all.length == 0) { all.push(COLOR_TEXT(..._color_option), char); }else{ all.push(char) } return true; } } }); output.push(all.join('')) output.push(COLOR_RESET()) return output.join('') } function ParseCommand(command) { let hmx = new Hemex(); hmx.setText(command); hmx.of(() => !hmx.isLetter()); if(!hmx.isLetter()) { return false } let onlyArgs = false; let commandName = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$'])); if(hmx.isEnd() && !hmx.isWhiteSpace()) { return false } hmx.readWhiteSpace(); let args = []; let xargs = [], operation = 'option'; hmx.beginPosition(); hmx.while(()=>{ if(hmx.include('--') && operation == 'option') { xargs.length && ( args.push({ type: 'data', data: xargs.join('') }), xargs = [] ); hmx.beginPosition(); hmx.include('--', true); let argumentkey = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$'])); if(argumentkey == false) { hmx.rejectPosition(); return true; } args.push({ type: "argument", data: argumentkey }); hmx.acceptPosition(); hmx.readWhiteSpace(); return true; } if(hmx.include('-') && operation == 'option') { xargs.length && ( args.push({ type: 'data', data: xargs.join('').trim() }), xargs = [] ); hmx.beginPosition(); hmx.nextChar(); let argumentkey = hmx.of(() => hmx.isLetter() || hmx.isNumber()); if(argumentkey == false) { hmx.rejectPosition(); return true; } argumentkey.split('').forEach(e => { args.push({ type: "flag", data: e }) }) hmx.acceptPosition(); hmx.readWhiteSpace(); return true; } let char; if((char = hmx.includes(['\'','"'])) && operation == 'option') { xargs.length && ( args.push({ type: 'data', data: xargs.join('') }), xargs = [] ); let escapeChar = char[0]; hmx.nextChar(); let data = []; hmx.while(() => { let char = hmx.getChar(); switch(hmx.getChar()) { case escapeChar:{ hmx.nextChar(); return false; } default:{ data.push(char); hmx.nextChar(); return true; } } }); args.push({ type: "string", data: data.join('') }) hmx.readWhiteSpace(); return true; } xargs.push(hmx.getChar()); if(hmx.isWhiteSpace()) { operation = 'option'; }else{ operation = 'data'; } hmx.nextChar(); if(hmx.isEnd()) { return true; }else{ args.push({ type: "data", data: xargs.join('') }) return false; } }); onlyArgs = hmx.getPositionRange(); hmx.acceptPosition(); return [{ type: "cmdline", data: command },{ type: "commandname", data: commandName },{ type: "arguments", data: onlyArgs }, ...args] } function generatepipe() { pausedInput = true; let events = {}; let gen = { stdin: { setPaused(boolean){ pausedInput = Boolean(boolean); }, async readline(){ gen.stdin.setPaused(false); gen._sys.idleReadline = true; return await new Promise(ok => { events['readline'] = (result) => { gen.stdin.setPaused(true); gen._sys.idleReadline = false; ok(result) events['readline'] = null; }; }) }, async getchar(){ gen.stdin.setPaused(false); gen._sys.idleChar = true; return await new Promise(ok => { events['read'] = (result) => { gen.stdin.setPaused(true); gen._sys.idleChar = false; events['read'] = null; ok(result) }; }) } }, stdout: { async write(...args){ term.write(args.map(e => e.toString()).join(' ')) }, async writeln(...args){ term.writeln(args.map(e => e.toString()).join(' ')) } }, stderr: { async write(...args){ term.write(COLOR_TEXT(255,0,0)); term.write(args.map(e => e.toString()).join(' ')) term.write(COLOR_RESET()); }, async writeln(...args){ term.write(COLOR_TEXT(255,0,0)); term.writeln(args.map(e => e.toString()).join(' ')) term.write(COLOR_RESET()); } }, _sys:{ idleReadline: false, idleChar: false, triggerReadline(text){ if(events['readline']) events['readline'](text) }, triggerChar(text){ if(events['read']) events['read'](text) }, destroy(){ gen.stdin.setPaused(false); events = void 0; gen._sys.idleReadline = false; gen._sys.idleChar = false; gen._sys = void 0; gen.stderr = void 0; gen.stdin = void 0; gen.stdout = void 0; activeProgram = false; } } }; activeProgram = gen; return gen; } async function ExecuteCommand(command, cmdline) { let Namespace = await CommandNamespace(command); if(Namespace == null) { return } try { await new Promise(async (ok,reject) => { resetUserSpace(); let program = new Namespace(generatepipe()); program.exit = () => ok(); try{ let t = program.main(cmdline); if(t?.constructor?.name == 'AsyncFunction') { await t; } }catch(e){ reject(e) } }) } catch(exception) { term.writeln(''); term.write(COLOR_TEXT(255,0,0)); term.writeln('Yazılım hatası:'); term.writeln('========================='); term.write(COLOR_RESET()); term.writeln(exception.message); term.writeln(exception.stack.replace(/\n/g,'\r\n')); term.write(COLOR_TEXT(255,0,0)); term.writeln('========================='); term.write(COLOR_RESET()); } finally { pausedInput = false; activeProgram = void 0; } } async function InspectRepo() { if(CommandNamespace.repos.find(e => e.downloaded == false)) { term.writeln(COLOR_RESET()+"\r\nUpdating repos....") await wait(100); }else{ term.writeln(''); } for(const repo of CommandNamespace.repos) { if(repo.downloaded == false) { term.writeln(`Downloading:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`); await wait(100); let file = await DownloadRepoMetapack(repo.endpoint); repo.packages = file; term.writeln(`Downloaded:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`); await wait(100); repo.downloaded = true; } } return } async function CommandNamespace(command) { let package = false; if(!CommandNamespace.namespaces.has(command)) { await InspectRepo(); for(const repo of CommandNamespace.repos) { for (const repopackage in repo.packages) { let packageName = repopackage; let meta = repo.packages[repopackage]; let _command = meta.commands.find(_command => command == _command); if(_command) { package = [packageName,meta]; } } } if(package == false) { term.writeln(COLOR_TEXT(255,0,0) + "'" + command + "' not found !" + COLOR_RESET()); }else{ term.writeln([ COLOR_TEXT(0,255,0), package[0], COLOR_TEXT(200,200,200), " paketine ait olan ", COLOR_TEXT(0,255,0), command, COLOR_TEXT(200,200,200), " komutunu kullanabilmek için aşağıdaki komutunu çalıştırın" ].join('') + "\r\n\n" + CommandColorize(`load '${package[0]}' from 'official'`)+ "\n" ); } }else{ return CommandNamespace.namespaces.get(command); } } function wait(ms) { return new Promise(ok => setTimeout(() => ok(),ms)); } async function DownloadRepoMetapack(endpoint) { let request = await fetch(endpoint,{ method: "get", cache: "force-cache", priority: "high", redirect: "follow", referrerPolicy: "no-referrer" }); await wait(100); try{ let response = await request.json(); return response; }catch { return null } } CommandNamespace.namespaces = new Map(); CommandNamespace.repos = [{ name: "official", endpoint: new URL('/console/official/packages.json',window.location), downloaded: false, packages: {} }]; class SystemLoad{ stdin = null; stdout = null; constructor(pipe){ this.stdin = pipe.stdin; this.stdout = pipe.stdout; } printhelp() { this.stdout.writeln('Kullanım şekli: '); this.stdout.writeln('ExampleProgram paketini kurmak için aşağıdaki komutu yazmalısınız\r\n'); this.stdout.writeln( CommandColorize(`load 'ExampleProgram'`)+"\r\n" ); } async main(args) { let m = false, nargs = args.filter(({type}) => { if(type == "arguments") return m = true, false; return m; }); let packname; if(nargs[0].type == "string") { packname = nargs[0].data; }else{ this.printhelp(); this.exit(); return; } if(CommandNamespace.repos.find(e => e.downloaded == false)) { this.stdout.writeln(COLOR_RESET()+"\r\nUpdating repos....") }else{ this.stdout.writeln(''); } for(const repo of CommandNamespace.repos) { if(repo.downloaded == false) { this.stdout.writeln(`Downloading:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`); await wait(100); let file = await DownloadRepoMetapack(repo.endpoint.href); if(file == null){ continue } repo.packages = file; this.stdout.writeln(`Downloaded:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`); await wait(100); repo.downloaded = true; } } let endpoints = CommandNamespace.repos.map(e => e.packages[packname] && e.packages[packname].endpoints.map(endpoint => new URL(endpoint,e.endpoint))).filter(e => !!e) if(endpoints.length == 0) { term.writeln(COLOR_TEXT(255,0,0) + "'" + packname + "' repo not found !" + COLOR_RESET()); await wait(100); this.exit(); return; } for (const endpoint of endpoints[0]) { let href = endpoint.href; this.stdout.writeln(`Packet downloading :${COLOR_TEXT(0,255,0)} ${packname} ${COLOR_RESET()} ${endpoint.href}`); await wait(100); let request = await fetch(href,{ method: "get", cache: "force-cache", priority: "high", redirect: "follow", referrerPolicy: "no-referrer" }); this.stdout.writeln(`Packet unzip to :${COLOR_TEXT(0,255,0)} /mount/xpack/${packname}/ ${COLOR_RESET()}`); await wait(100); let script = await request.text(); try{ this.stdout.writeln(`Analyzing..`); await new Promise(ok => setTimeout(() => ok(),1000)); (new Function(script))(); this.stdout.writeln(`Process success`); await wait(100); }catch{ this.stderr.writeln(`Process error`); await wait(100); } } this.exit(); } }; CommandNamespace.namespaces.set('load', SystemLoad);