19

I have read about Fabrice Bellard's linux simulation in browser.

How does Linux emulator in Javascript by Fabrice Bellard work?

Today I stumbled upon this site, where they are simulating full linux terminal in browser, I am able to run python, perl etc. I know they are running their site on node.js, but I couldn't figure out how they exactly simulating the terminal.

http://runnable.com/UWRl3KlLuONCAACG/read-files-from-filesystem-in-python

Community
  • 1
  • 1
DevC
  • 7,055
  • 9
  • 39
  • 58
  • 3
    through ajax request...try to open firefox webconsole and you can see a series of ajax requests :-) – StaleMartyr Oct 24 '13 at 08:54
  • If you only want the UI part of that, take a look at this: https://stackoverflow.com/questions/12905726/whats-the-best-way-to-simulate-a-dos-or-terminal-screen-in-a-web-page/64217301#64217301 – Danziger Oct 05 '20 at 23:08

2 Answers2

22

The full linux is http://docker.io, the rest is https://github.com/Runnable/dockworker

We're not simulating the terminal but as Kyle says, replicating the terminal over websockets (with an ajax fallback).

In the browser we're using https://github.com/chjj/term.js which was derived from Fabrice Bellard's emulator. It handles the output, and also the keystroke capture.

generalhenry
  • 17,227
  • 4
  • 48
  • 63
  • perfect.. I was looking for something like this. – DevC Dec 31 '13 at 06:17
  • 2
    I have a simplified version serving up nodeschool.io workshops: https://github.com/generalhenry/expose-bash-over-websockets https://github.com/generalhenry/nodeschool-interactive https://github.com/generalhenry/docker-gc https://github.com/generalhenry/nodeschool-dockerfiles – generalhenry Dec 18 '14 at 23:37
  • This question is from 4years ago but I'm actually trying to do that and I'm stuck... Someone has an idea how to put a Docker terminal in a Meteor app ? I have founded https://github.com/mafintosh/docker-browser-console but I can't make it works for me. I will appreciate any help – Jerome Jan 16 '17 at 08:46
4

Let me prefix this by saying it is NOT a good idea to do this.

But, You can spawn a shell and use web-sockets or XMLHttpRequests to push keypresses to the spawned server process. Here's a working example of one that runs on windows. Unfortunately, I didn't get around to hooking up / figuring out Ctrl+c. But, you should get the gist of it.

  require("underscore");

  var Server = {},
      express = require("express"),
      path = require("path"),
      sys = require("sys"),
      application_root = __dirname;

  global.Server = Server;
  Server.root = application_root;
  global.app = express();

  Server.setup = require("./lib/setup.js").setup({
    //redis: require("./lib/redis-client").createClient(),
    app: app, 
    //mongoose : require("mongoose"),
    io : require("socket.io"),
    express : express,
    port: 1773,
    paths : {
      views :  path.join(application_root,"app","views"),
      root : path.join(application_root,"public"),
      controllers : path.join(application_root,"app","controllers"),
      models : path.join(application_root,"app","models")
    }
  });

  var proc = require('child_process'),
      cmd;

  app.socket.on('connection', function(socket) {
    if (!cmd) {
      //console.log('spawning cmd');
      cmd = proc.spawn('cmd');

      //console.log(cmd?'CMD started':'CMD not started');

      if (cmd.stdout) {
        //console.log('stdout present');
        cmd.stdout.on('data',function(data) {
          if (data) {
            //console.log("data: "+data);
            socket.emit('cmd', ""+data);
          }
        });
      }
      if (cmd.stderr) {
        cmd.stderr.on('data', function(data) {
          //console.log('stderr present');
          if (data) {
            socket.emit('cmd', ""+data);
          }
        });
      }

      cmd.on('exit', function() {
        //console.log('cmd exited');
        socket.emit('cmd', '[CMD Shutdown]');
        if (cmd) {
          cmd.kill();
          cmd = null;
        }
      });
    }

    socket.on('sendCmd', function(data) {
      if (data && data.buffer) {
        var kB = data.buffer.replace("\r","\n");
        if (cmd && cmd.stdin) {
          cmd.stdin.write(kB);
        }
      }
    });

    socket.on('disconnect', function() {
      console.log('connection closed');
      if (cmd) {
        cmd.stdin.end(); //.kill();
        if (cmd) {
          cmd.kill();
          cmd = null;
        }
      }
    });
  });

Edit: Actually, this is a portion of a working example. It's missing the client side where you capture and send the keystrokes to the server. But, it should give you the general idea.

Kyle Mueller
  • 116
  • 1
  • 3