Browse Source

Update with support for toml configuration.

master
liam beckman 1 year ago
parent
commit
c8664c1932
No account linked to committer's email address
14 changed files with 1399 additions and 1575 deletions
  1. 62
    4
      README.md
  2. 0
    414
      codemirror.bundle.js
  3. BIN
      demo-logo.png
  4. 0
    225
      demo.bundle.js
  5. BIN
      demo.png
  6. 0
    3
      header.html
  7. 0
    32
      index.html
  8. 1018
    240
      package-lock.json
  9. 3
    1
      package.json
  10. 88
    0
      process.js
  11. 114
    0
      process.toml
  12. 0
    380
      programs.js
  13. 114
    268
      server.js
  14. 0
    8
      tmp.py

+ 62
- 4
README.md View File

@@ -1,4 +1,4 @@
# demo
# demonic server

<img src="demo-logo.png" width=250/>

@@ -10,7 +10,7 @@ Try it out [here](https://liambeckman.com/code/demo).
<img src="demo.png"/>
</a>

# installation and running
# Installation and Running

```sh
# install dependencies
@@ -28,12 +28,70 @@ node server.js 12345
# edit server information
nano demo.js

# then you can connect to the server from a client (e.g. client-example.html)
# then you can connect to the server from a client (e.g. client-example.html)
```

# uninstallation
# Uninstallation

```sh
# remove this directory
rm -rfI demo
```

# Message Protocol

- Connection is established between client and server.

- Client sends server the command mode (and language if `mode` is set to 'code').

```json
{
"mode": "shell",
}
```

```json
{
"mode": "code",
"lang": "ruby",
}
```

- Client sends server data on every keypress.

- Server buffers the incoming data until a 'newline' charcter is received.

- Server finds the program named in the input, and sends the contents of the input buffer to that program.

- Server sends client the output of the command.

```json
{
"out": "Wow, I'm in a shell!"
}
```

- Client displays output on terminal.

- Server sends client the exit status of the command.

```json
{
"exit": 0
}
```

- Client displays user prompt on terminal.

## Client to Server

mode: Keyword to inform server of expected behavior. Possible options are 'shell' and 'code'.
lang: If mode is set to 'code', language specifies the respective programming language.
content: The commands or code sent by the user to be evaulted by the server.

## Server to Client

exit: Exit status of spawned process.
control: Keyword to inform client that spawned process will handle output of characters (e.g. vim). Disables writing client-side as well as buffering server-side.
out: STDOUT of the spawned process.
err: STDERR of the spawned process.

+ 0
- 414
codemirror.bundle.js
File diff suppressed because it is too large
View File


BIN
demo-logo.png View File


+ 0
- 225
demo.bundle.js
File diff suppressed because it is too large
View File


BIN
demo.png View File


+ 0
- 3
header.html View File

@@ -1,3 +0,0 @@
<!-- Demo and Codemirror bits -->
<script src="demo.bundle.js"></script>
<script src="docs.bundle.js"></script>

+ 0
- 32
index.html View File

@@ -1,32 +0,0 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="node_modules/xterm/dist/xterm.css" />
<link rel="stylesheet" href="node_modules/xterm/dist/addons/fullscreen/fullscreen.css" />
<script src="node_modules/xterm/dist/xterm.js"></script>
<script src="node_modules/xterm/dist/addons/terminado/terminado.js"></script>
<script src="node_modules/xterm/dist/addons/fullscreen/fullscreen.js"></script>
</head>
<body>
<div class="container">
<div id="terminal-container"></div>
</div>
<script>
terminado.apply(Terminal);

Terminal.applyAddon(fullscreen); // Apply the `fullscreen` addon
var term = new Terminal(),
protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://',
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + "/websocket";
sock = new WebSocket(socketURL);

sock.addEventListener('open', function () {
term.terminadoAttach(sock);
});

term.open(document.getElementById('terminal-container'));
term.toggleFullScreen(); // Now the terminal should occupy the full viewport
</script>
</body>
</html>


+ 1018
- 240
package-lock.json
File diff suppressed because it is too large
View File


+ 3
- 1
package.json View File

@@ -32,11 +32,13 @@
"https": "^1.0.0",
"jquery": "^3.4.1",
"mysql": "^2.8.0",
"node-pty": "^0.9.0",
"prettier": "^1.15.3",
"prompt": "^1.0.0",
"readline": "^1.3.0",
"readline-sync": "^1.4.9",
"spawn-sync": "^2.0.0",
"toml": "^3.0.0",
"webpack": "^4.34.0",
"websocket": "^1.0.28",
"ws": "^6.2.1",
@@ -44,6 +46,6 @@
},
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.9.0",
"webpack-cli": "^3.3.4"
"webpack-cli": "^3.3.11"
}
}

+ 88
- 0
process.js View File

@@ -0,0 +1,88 @@
const {spawn} = require('child_process');
const concat = require('concat-stream');
const fs = require('fs');
const toml = require('toml');
const pty = require('node-pty');

let processes = [];

class Process {
constructor(name, comm) {
this.name = name;
this.comm = comm;
this.options = {
detached: true,
stdio: 'inherit',
};
}
}

let parsed = {};
fs.createReadStream('process.toml', 'utf8').pipe(concat((data) => {
parsed = toml.parse(data);
// '--rlimit-nproc=100',
// '--rlimit-as=50000000',
const sandbox = 'firejail';
const args = [
'--quiet',
'--net=none',
'--hostname=demonic',
'--nice=10',
'--private-home=/tmp/demonic/bin',
'sh',
'-c',
];

for (const prop in parsed) {
const process = parsed[prop];
let name = process.name.split(' ');
let userArgs = false;
let command = process.comm;
if (Array.isArray(command)) {
command = command.join(';');
}

if (process.args) {
userArgs = process.args;
}

// Program
const comm = (arg) => {
if (userArgs) {
return new pty.spawn(shell, args.concat(`${command} ${arg}`), this.options);
}

return new pty.spawn(shell, args.concat(command), this.options);
}

// Language
if (process.file) {
const comm = (code) => {
let path = '';
const dir = '/tmp/demonic';

// Create random file name with correct file extension.
// Verify that file with same name does not exist.
while (path.length == '') {
const id = Math.floor(Math.random() * 1e3);
path = `${dir}/tmp-${id}`;
}
// Write code to file.
fs.writeFileSync(`${path}.${process.file}`, code);

let pathCommand = command.replace(/<path>/g, path);
pathCommand = pathCommand.replace(/<dir>/g, dir);

return new pty.spawn(shell, args.concat(pathCommand));
}

processes.push(new Process(name, comm));
continue;
}

processes.push(new Process(name, comm));
}
}));

module.exports = {Process, processes};


+ 114
- 0
process.toml View File

@@ -0,0 +1,114 @@
# name: Name of the program or language. Used to identify which process to spawn (e.g. 'ls').
# Does not need to match the command of the process. Only needs to be unique.
#
# comm: Command of the process to spawn (e.g. 'ls').
#
# args: Whether arguments from the client should be appended to 'comm' before spawning.
# default: false
#
# draw: Whether the client is expected to handle the output of the spawned process.
# If false, the client should cease output to the terminal for the duration of the process.
# default: true
#
# file: File extension of the language (e.g. 'c', 'cpp', 'rs').

# programs

[palindrome]
name = 'palindrome pal'
comm = './programs/palindrome'
args = true

[ls]
name = 'ls'
comm = 'ls'

[vim]
name = 'vim'
comm = 'vim'
draw = false

[prime]
name = 'prime'
comm = './programs/prime'
args = true

[withfeathers]
name = 'withfeathers wf'
comm = 'python3 ./programs/withfeathers.py'
args = true

# languages

[c]
name = 'c'
file = 'c'
comm = [
'gcc -o <path> <path>.c',
'<path>',
]

[cpp]
name = 'c++ cpp'
file = 'cpp'
comm = [
'g++ -o <path> <path>.cpp',
'<path>',
]

[go]
name = 'go'
file = 'go'
comm = 'go run <path>'

[haskell]
name = 'haskell'
file = 'hs'
comm = 'ghci <path>'

[java]
name = 'java'
file = 'java'
comm = [
'javac <path>',
'class=$(basename -- <path>)',
'class="\<path>%.*"',
'java $class',
]

[javascript]
name = 'javascript'
file = 'js'
comm = 'node <path>'

[python]
name = 'python'
file = 'py'
comm = 'python3 <path>'

[ruby]
name = 'ruby'
file = 'rb'
comm = 'ruby <path>'

[rust]
name = 'rust'
file = 'rs'
comm = [
'rustc -o <path> <path>.rs',
'<path>',
]

[schema]
name = 'scheme'
file = 'scm'
comm = 'scheme <path>'

[markdown]
name = 'markdown'
file = 'md'
comm = [
'pandoc -f markdown -t html -s <path>.md -o <path>.html -H <dir>/head.html',
'echo <path>.html',
]


+ 0
- 380
programs.js View File

@@ -1,380 +0,0 @@
const { spawn, exec } = require('child_process');

const programs = [];

class Program {
constructor(name, command) {
this.name = name;
this.command = command;
this.error = null;
this.message = null;

this.child = spawn('ls', this.options);

this.options = {
detached: true,
stdio: 'pipe',
};

this.options_shell = {
detached: true,
stdio: 'pipe',
shell: true,
cwd: 'programs/wyeast',
};

// '--rlimit-nproc=100',
// '--rlimit-as=50000000',
this.sandbox = [
'--quiet',
'--net=none',
'--hostname=demonic',
'--nice=10',
'--private-home=/srv/chroot/demo/bin',
'--chroot=/srv/chroot',
];

programs.push(this);
}
echo(name, command) {
console.log(`My name is ${this.name} and my command is ${this.command}.`);
}
run(command) {
command();
}
getError() {
return this.error;
}
setError(message) {
this.error = message;
}
getMessage() {
return this.message;
}
setMessage(message) {
this.message = message;
}
getSandbox() {
return this.sandbox;
}
setSandbox(sandbox) {
this.sandbox = sandbox;
}
}

let palindrome = new Program(
["palindrome", "./palindrome"],
function() {
return spawn('programs/palindrome.out', this.options);
});

let cat = new Program(
["cat"],
function() {
return spawn('cat', [`./files/${commands[1]}`], this.options);
});

let ls = new Program(
["ls"],
function() {
let list = "";
for (let i = 0; i < programs.length; i++) {
list += programs[i].name[0] + "\n";
}
for (let i = 0; i < files.length; i++) {
list += files[i] + "\n";
}
console.log('setting message to:', list);
return list;
//return this.getMessage();
//return spawn('ls', this.options);
});

let matriz = new Program(
["matriz", "./matriz"],
function() {
/*
for (i = 0; i < commands.length; i++) {
console.log(`!!: ${commands[i]}`);
}
*/
if (commands[3]) {
return spawn('programs/matriz.sh', [ `${commands[1]}`, `./files/${commands[2]}`, `./files/${commands[3]}`], this.options);
}
else {
console.log(`!!: ${commands[0]} ${commands[1]} ${commands[2]}`);
return spawn('programs/matriz.sh', [ `${commands[1]}`, `./files/${commands[2]}`], this.options);
}
});

let prime = new Program(
["prime", "./prime"],
function() {
if (commands[1] <= 1000000) {
return spawn('programs/prime.out', [`${commands[1]}`], this.options);
}

else {
this.setError("Prime number must be less than or equal to 1000000.\n");
}
});

let withfeathers = new Program(
["withfeathers", "python withfeathers"],
function() {
return spawn('python3', ['programs/withfeathers/main.py', `${commands[1]}`], this.options);
});

let devilish = new Program(
["devilish", "./devilish"],
function() {
let sandbox = sandbox_common.push('/home/demo/bin/devilish.out');
return spawn('firejail', sandbox, this.options);
});

let zigzag_server = new Program(
["zigzag-server"],
function() {
return spawn('python3', ['-u', 'programs/zigzag/zigzag-server.py'], this.options);
});

let zigzag_client = new Program(
["zigzag-client"],
function() {
return spawn('programs/zigzag/zigzag-client.out', [`127.0.1.1`, `${commands[1]}`], this.options);
});

let wyeast = new Program(
["wyeast"],
function() {
return spawn('./buildworld && ./wyeast', this.options_shell);
});

let voy = new Program(
["voy"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}
return spawn('voy', args, this.options);
});

let markdown = new Program(
["markdown"],
function() {
console.log('commands:', commands);
srcfile = commands[1];
outfile = commands[1] + '.html';
const run = `
pandoc -f markdown -t html -s ${srcfile} -o ${outfile} -H header.html
mkdir -p /var/www/demo/demo-docs/tmp
out=$(basename ${outfile})
src=$(basename ${srcfile})
mv ${outfile} /var/www/demo/demo-docs/tmp
mv ${srcfile} /var/www/demo/demo-docs/tmp/$src.md
echo https://demo.liambeckman.com/tmp/$out
`;
console.log(run)
return spawn(run, {
shell: true,
});
});

// sandboxed programming langauges

let gcc = new Program(
["gcc"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}
console.log('args:', args);

let run = `
gcc -o ${args[0]} ${args[0]}.c &&
while [ ! -f ${args[0]} ]; do
sleep 1;
done;
${args[0]}
`;

run = run.replace(/\/srv\/chroot/g,'');
run = run.replace(/(?:\r\n|\r|\n)/g,'');
console.log('run:', run);

let sandbox = [...gcc.getSandbox()];
sandbox.push('sh');
sandbox.push('-c');
sandbox.push(run);
console.log('sandbox:', sandbox);
return spawn('firejail', sandbox, this.options);
});

let gpp = new Program(
["g++", "gpp"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}
console.log('args:', args);

let run = `
g++ -o ${args[0]} ${args[0]}.cpp &&
while [ ! -f ${args[0]} ]; do
sleep 1;
done;
${args[0]}
`;

run = run.replace(/\/srv\/chroot/g,'');
run = run.replace(/(?:\r\n|\r|\n)/g,'');

let sandbox = [...gpp.getSandbox()];
sandbox.push('sh');
sandbox.push('-c');
sandbox.push(run);
return spawn('firejail', sandbox, this.options);
});


let go = new Program(
["go", "golang"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}

let run = `${args}`;
run = run.replace('/srv/chroot','')

let sandbox = [...go.getSandbox()];
sandbox.push('go');
sandbox.push('run');
sandbox.push(run + '.go');
return spawn('firejail', sandbox, this.options);
});

let java = new Program(
["java"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}

let run = `
javac ${args[0]};
cd /tmp;
FILE=$(basename -- ${args[0]});
FILE="\${FILE%.*}";
java $FILE;
`;

run = run.replace(/\/srv\/chroot/g,'');
run = run.replace(/(?:\r\n|\r|\n)/g,'');

let sandbox = [...java.getSandbox()];
sandbox.push('sh');
sandbox.push('-c');
sandbox.push(run);
return spawn('firejail', sandbox, this.options);
});

let haskell = new Program(
["haskell"],
function() {
return spawn('ghci', this.options);
});


let javascript = new Program(
["javascript", "node"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}

let run = `${args}`;
run = run.replace('/srv/chroot','')

let sandbox = [...javascript.getSandbox()];
sandbox.push('node');
sandbox.push(run);
return spawn('firejail', sandbox, this.options);
});

let python = new Program(
["python", "python3"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}
console.log('args:', args);

let run = `${args}`;
run = run.replace('/srv/chroot','')

let sandbox = [...python.getSandbox()];
sandbox.push('python3');
sandbox.push(run);
return spawn('firejail', sandbox, this.options);
});


let ruby = new Program(
["ruby"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}

let run = `${args}`;
run = run.replace('/srv/chroot','')

let sandbox = [...ruby.getSandbox()];
sandbox.push('ruby');
sandbox.push(run);
return spawn('firejail', sandbox, this.options);
});

let rust = new Program(
["rust", "rustc"],
function() {
let args = [];
for (let i = 1; i < commands.length; i++) {
args.push(commands[i]);
}

let run = `
rustc -o ${args[0]} ${args[0]}.rs;
${args[0]}
`;

run = run.replace(/\/srv\/chroot/g,'');
run = run.replace(/(?:\r\n|\r|\n)/g,'');
console.log('run:', run);

let sandbox = [...rust.getSandbox()];
sandbox.push('sh');
sandbox.push('-c');
sandbox.push(run);
console.log('sandbox:', sandbox);
return spawn('firejail', sandbox, this.options);
});



let scheme = new Program(
["scheme"],
function() {
return spawn('scheme48', this.options);
});

module.exports = programs;

+ 114
- 268
server.js View File

@@ -1,296 +1,142 @@
const BSON = require('bson');
const WebSocket = require('ws');
const fs = require('fs');
const server = require('./config.js');
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server });
const programs = require('./programs.js');
const BSON = require('bson');

// heartbeat interval (attempts to reconnect if connection is broken)
function noop() {}

function heartbeat() {
this.isAlive = true;
}

const interval = setInterval(function ping() {
wss.clients.forEach(function each(ws) {
if (ws.isAlive === false) return ws.terminate();

ws.isAlive = false;
ws.ping(noop);
});
}, 3000);

// reference to spawned child process.
// actions for child's stdout, stdin, stderr, close
// are handled below.

console.log("Waiting for clients...");
server.listen(process.argv[2] || 8181);

wss.on('connection', function connection(ws) {
let child = programs[0].child;
console.log("Client connected!");
let first = true;
const {Process, processes} = require('./process.js');
const {spawn, exec} = require('child_process');

ws.isAlive = true;
ws.on('pong', heartbeat);

files = ["m1", "m2"];
userPrompt = "> ";

ws.on('message', async function incoming(message) {
let command = '';
let code = '';
let language = '';
let mode = '';

try {
//console.log('message:', message);
message = JSON.parse(message);

if (message.command) {
command = message.command;
}

if (message.code) {
code = message.code;
command = message.language;
mode = message.mode;
}
} catch(err) {
command = message;
}

//console.log('command:', command);
//console.log('COMMAND:', command);

if (mode == 'code') {
let language = message.language;
let code = message.code;
let id = Math.floor(Math.random() * 1e6);
file = `/srv/chroot/tmp/tmp_${id}`;

switch (language) {
// C
case 'text/x-csrc':
write(file, code, '.c');
command = `gcc ${file}`;
break;
// C++
case 'text/x-c++src':
write(file, code, '.cpp');
command = `g++ ${file}`;
break;
case 'go':
write(file, code, '.go');
command = `go ${file}`;
break;
// Java
case 'text/x-java':
file = `/srv/chroot/tmp/Hello.java`;
write(file, code);
command = `java ${file}`;
break;
case 'javascript':
write(file, code);
command = `node ${file}`;
break;
case 'markdown':
write(file, code);
command = `markdown ${file}`;
break;
case 'python':
write(file, code);
command = `python3 ${file}`;
break;
case 'ruby':
write(file, code);
command = `ruby ${file}`;
break;
case 'rust':
write(file, code, '.rs');
command = `rustc ${file}`;
break;
}
const wss = new WebSocket.Server({ server });
const port = process.argv[2] || 8181;
server.listen(port);
console.log('Waiting for clients at ws://localhost:' + port);

wss.on('connection', (ws) => {
console.log('Client connected!');

// An ongoing process is present.
// Incoming data should be sent to it's STDIN.
let process = false;
let child = {};
let program = {};

userPrompt = '> ';
buffer = [];
let obj = {};
let data = '';

ws.on('message', (message) => {
obj = JSON.parse(message);
if (obj.data != null) {
data = obj.data;
}
console.log(obj.lang != null && obj.code != null);

if (command == "ping") {
ws.send("pong");
return;
}
// Language
if (obj.lang != null && obj.code != null) {
const loading = {'loading': 'true'};
ws.send(JSON.stringify(loading));

else if (command == "close") {
ws.close();
return;
program = findProcess(obj.lang);
ws.send(JSON.stringify({draw: false}));
child = program.comm(obj.code);
}

if (first == true) {
first = false;

if (message == ":(){ :|:& };:" || command == "sudo rm -rf /*") {

first = true;
let song = "Daisy, Daisy,\n" +
"Give me your answer, do!\n" +
"I'm half crazy,\n" +
"All for the love of you!\n"
// Program
else {
// If a child process is ongoing.
if (process) {
let command = data;

ws.send(song , function ack(error) {
console.error("ERROR:", error);
});
ws.send(userPrompt, function ack(error) {
console.error("ERROR:", error);
});
child.write(command);
return;
}

else if (message == 'prompt') {
ws.send(userPrompt, function ack(error) {
console.error("ERROR:", error);
});
// No process is ongoing, identify command and spawn process.
let command = buff(buffer, data);
console.log('command:', command);
if (command == null) {
return;
}

else {
console.log('command:', command);
commands = command.split(" ");
let found = false;

// for all programs
for (i = 0; i < programs.length; i++) {
// for all names and aliases of each program
for (n = 0; n < programs[i].name.length; n++) {
// if the first word of the user command matches a name/alias
if (commands[0] === programs[i].name[n]) {
console.log(`Running ${programs[i].command}`);
child = eval(programs[i].command)();
if (typeof child == 'function') {
child = await child();
}

// emulates stderr
if (programs[i].getError()) {
ws.send(programs[i].getError());
ws.send(userPrompt);
first = true;
programs[i].setError(null);
}

// emulates stdout
else if (programs[i].getMessage()) {
ws.send(programs[i].getMessage());
ws.send(userPrompt);
first = true;
programs[i].setMessage(null);
}


found = true;
break;
}
}
}

if (!found) {
first = true;
console.log("Invalid program.");
ws.send("Invalid program.\n", function ack(error) {
console.error("ERROR:", error);
});
ws.send(userPrompt, function ack(error) {
console.error("ERROR:", error);
});

child.kill("SIGINT");
}
// Close connection.
if (command == 'close') {
ws.close();
return;
}

//console.log('child:', child);
//console.log('typeof child:', typeof child);

// child is from "psuedo command" like "ls"
if (typeof child == 'string') {
let data = child;
ws.send(data, function ack(error) {
console.error("ERROR:", error);
});

first = true;
ws.send(userPrompt, function ack(error) {
console.error("ERROR:", error);
});
let commands = command.split(' ');
program = findProcess(commands[0]);
if (program == null) {
const err = {'err': `${commands[0]}: command not found\n`};
ws.send(JSON.stringify(err));
const exit = {'exit': 1};
ws.send(JSON.stringify(exit));
return;
}

// child is spawned process
else {
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
ws.send(data, function ack(error) {
console.error("ERROR:", error);
});
});

child.stderr.on('data', (data) => {
console.log(`stdout: ${data}`);
ws.send(data.toString(), function ack(error) {
console.error("ERROR:", error);
});
});

child.on('close', (code) => {
console.log(`child process exited with code ${code}`);
first = true;
child.kill("SIGINT");
ws.send(userPrompt, function ack(error) {
console.error("ERROR:", error);
});
});
// If program has 'draw' attribute set to false,
// inform client not to write to terminal (the program
// will do so.)
if (!program.draw) {
const obj = {draw: false};
ws.send(JSON.stringify(obj));
}

// Spawn child process and store reference in 'child' variable.
const args = commands.slice(1);
child = program.comm(args);
}

else {
// signals
if (command == "SIGINT") {
ws.send("SIGINT received.\n", function ack(error) {
console.error("ERROR:", error);
});
child.kill("SIGINT");
first = true;
}
if (command == "SIGTSTP") {
ws.send("SIGTSTP received.\n", function ack(error) {
console.error("ERROR:", error);
});
child.kill("SIGTSTP");
first = true;
}

// stdin
else {
console.log("writing to child:", command);
child.stdin.write(command + "\n");
}
}
// STDOUT
child.on('data', (data) => {
const out = {'out': data};
ws.send(JSON.stringify(out));
});

// STDERR
child.on('error', (data) => {
const err = {'err': data};
ws.send(JSON.stringify(err));
});

// termination
child.on('exit', (code) => {
const exit = {'exit': code};
ws.send(JSON.stringify(exit));
process = false;
});

process = true;
});
});


function write(file, code, ext = '') {
let filename = file + ext;
fs.writeFile(filename, code, err => {
if(err) {
return console.log(err);
}
});
console.log(`wrote ${code} to ${filename}`);
function buff(buffer, data) {
if (data.charCodeAt(0) == 13) {
command = buffer.join('');
buffer.length = 0;
return command;
}
else if (data.charCodeAt(0) == 127) {
buffer.pop();
}
else {
buffer.push(data);
}
return null;
}

function read(file) {
fs.readFile(file, (err, data) => {
if (err) throw err;
if(err) {
return console.log(err);
function findProcess(command) {
// For all processes.
for (const program of processes) {
for (const name of program.name) {
// If the first word of the user command matches a name/alias.
if (command == name) {
return program;
}
}
return data;
})
}

// If no available program was found.
return null;
}


+ 0
- 8
tmp.py View File

@@ -1,8 +0,0 @@
def greet():
name = input('Enter your name: ')
print('Hello', name)

def main():
greet()

main()

Loading…
Cancel
Save