开坛

NodeOS:一个用JavaScript写出来的操作系统

Node.js的大名相信IT界的同行们都有所耳闻,但NodeOS可能就鲜有人知道了。是的,没有写错,就是NodeOS,一个用Node.js编写的操作系统。NodeOS是一个基于Linux内核的操作系统,一些如硬件交互等关键的性能相关的工作当然还是需要Linux内核来处理了,但所有其他的操作系统功能都是通过Node.js来实现的。整个NodeOS的开发过程历时2年,这个项目的起因简单而迷人:“是否可能只用Node.js来编写一个操作系统呢?”

NodeOs进化历程

是时候做些改变

首先,Node.js自诞生以来所产生的成就相信大家都有目共睹。但操作系统却没见有多大的变化。Unix还是Unix,Linux还是Linux,Windows也还是那个Windows。

每个用户拥有独立的文件系统

NodeOS引进了一个有意思的范式:如果每个用户都有独立且隔绝的文件系统,那么文件系统的层级架构就变得很简单。因为用户的home目录事实上就变成了文件系统的根目录的层级结构了,这样每个用户就都能随心所欲的安装自己需要的软件,而不需要特殊的权限和配置了,因为这些东西默认就是安装在各自的根目录上面,根本不会影响到其他人。此外,这样做的话还能提高系统安全性。如果黑客攻破了某个用户的账户,那么他充其量也只能访问到该用户的所有文件而已,其他用户的内容他根本看不到。这样的话,黑客就不可能拿下整个操作系统了。

Node.js 和 NPM

其实仔细想想,一个用Node.js写的操作系统,那不就是意味着所有在NPM上的包都可以为这个操作系统所用吗?现在为止,NPM上面已经有210,735个软件包了。因为几乎每分钟都会有新的包增加到NPM上面,所以不出几年,NodeOS就会拥有上百万的应用了、

应用移植简单

因为整个NodeOS是基于Linux的内核的,所以所有为某个Linux发行版所编写的应用,只需要做很少的改动就能运行在NodeOS上面了。

不足之处

当前的NodeOS还不够完整。作为一个服务器操作系统的很多关键功能都还没有提供。比如,BASH工具集还没有实现,所以ps,tail,nano和grep这些你在Linux常用的功能都还没有。

另外,你还不能把它作为一个桌面操作系统来运行,因为现在还没有GUI的支持。当然,你可以通过JavaScript写几行代码来实现这些工具。但是,默认没有提供这些功能的话,毕竟说不过去了。

安装和示例

Using Docker

The easiest and quickest way to try out NodeOS is by using the following:

  1. A computer with either Mac OSX or Linux. It might work with Windows, but I did not try it.
  2. Docker.

Once you installed Docker, running an instance of NodeOS is easy. All you need to do is execute the following command, and Docker does all the magic:

sudo docker run -t -i nodeos/nodeos

2

When you run the aforementioned command, Docker automatically downloads the disk image for NodeOS from a repository and performs the installation of NodeOS inside a virtual machine. Once the installation is completed, it opens an SSH session to the NodeOS shell.

Without docker

There are some reasons why you would want to avoid using Docker, and one being the latest NodeOS version. At the time of writing, the last change to the Docker image of NodeOS was performed two months ago, while the development version was updated six days ago. So, if you want to use the latest version you should definitely get the source code. That’s not too difficult, but it takes a long time. You will need:

  1. A computer with Linux. You can compile it on OS X, but it will take longer since it has to make a cross compilation. The same goes for Windows.
  2. The Linux build utilities (make, g++, gcc, autoconf).
  3. Qemu.
  4. Time. Seriously, a lot.

Once you have everything, you can proceed with the source code compilation:

  1. Download the project source code: bash git clone git@github.com:NodeOS/NodeOS.git.
  2. Compile it by running following commands: cd NodeOS and npm install.
  3. I am going to quote, word by word, the official documentation: “Pick some microwave popcorn and go to see a movie. No, really, do it.”. Yes, it will take that much time, so do something interesting in the meantime.
  4. Run bash npm start to run NodeOS inside Qemu.

Is it working?

Once the installation is completed, we can check if it is working by executing inside the NodeOS shell the command ls. An output like this should show up:

[ 'etc', 'lib', 'lib64', 'root', 'bin', 'sys', 'usr', 'share', 'proc' ]

If it does, it means some basic commands are working. But, what if we want to display the network card’s IP address? Under Linux, there’s a command called ifconfig that does just that; let’s try it:

command not found: ifconfig

It looks like the command ifconfig is missing. That is because NodeOS does not have a default ifconfig command. Now, what? Well, it is simple; NodeOS has an integrated package manager (like aptor yum), called npkg, which is based on Node’s NPM and is easy to use. Installing ifconfig is as simple as running the following command:

npkg install bin-ifconfig

If all went well, the command ifconfig should now be available in the shell. If we try to execute it again, an output like this shows up (I put a random MAC address and IP address for obvious reasons):

eth0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
  ether 01:23:45:67:89:ab 
  inet6 f0cd::ef01:0203:0405:181%en1 prefixlen 64 scopeid 0x5 
  inet 192.168.0.21 netmask 0xffffff00 broadcast 192.168.0.21
  nd6 options=1<PERFORMNUD>
  media: autoselect
  status: active

If your output looks kind of like that, then it is working. You’ve successfully installed your first NodeOS application: ifconfig.

It is working. However, what do we do now with the OS?

What is the point of having an operating system written in Node.js if you can do the same things (or even fewer things) that you can do on Ubuntu or any other Linux distribution? Well, the whole point is everything is developed by using nothing more than Node.js. It also means we can develop our applications using nothing more than Node.js. For example, NodeOS does not have a default implementation for the command man, which is used on Linux to display manual pages of other commands. Fear not, implementing it is easy. How, I hear you ask? Simple.

3

First, let’s install a text editor called Hipster so we can create and edit files by executing the following command: npm install -g hipster@0.15.0. This file editor is simple, and definitely not something I would use as an editor for anything else, but it is good enough in this case. Creating files with Hipster is really simple, just run hip filename, like hip package.json; to save press Ctrl + s and to exit press Ctrl + q. For this example I am going to use a code developed by one of the main NodeOS developers, I have not actually implemented it, myself. The original code for our example can be found in the node-bin-man Git repository.

Let’s get back to creating our first NodeOS application. As with every Node.js application (or NPM package), we start by creating a package.json file, as in the following example:

{
  "name": "bin-man",
  "version": "0.0.1",
  "description": "Format and display manual pages",
  "bin": {
    "man": "man.js"
  },
  "repository": "https://github.com/groundwater/node-bin-man",
  "author": "groundwater",
  "license": "MIT",
  "dependencies": {
    "blessed": "~0.0.22"
  }
}

The parameters name, version, author, repository, license, and description are self-explanatory. The bin collection is a JSON key/value object containing the command name and an associated JavaScript file. In our example, the man command is associated with the file man.js. The collection, dependencies, contains a list of NPM packages that are needed to use this application. In our example, the author of the code included Blessed, a curses-like library with a high-level terminal interface API for Node.js.

Now let’s go to the main part, the actual code.

#!/usr/bin/env node

This part is called “shebang”. It is not actually required by NodeOS, but it tells an operating system how to execute the following code. In our case, it tells the interpreter that everything needs to be executed with the command /usr/bin/env node.

var fs = require('fs');
var blessed = require('blessed');

Just like in Node.js, the function require() loads the selected package into memory and saves it to the specified variable.

var arg = process.argv[2] || 'bin-man';

The standard behavior of a man command is to tell a manual about itself if no other command is specified. Our code example is doing the same: If no argument is specified for the second parameter (the first being man itself), it defaults to bin-man.

var path = process.env.HOME + "/lib/node_modules/" + arg + "/README.md";

try{
  var readme = fs.readFileSync(path, 'utf-8');
}catch(e){
  console.log('No README.md for Package ',arg);
  process.exit(-1);
}

At this point, the program checks if a readme file exists for the given application. In NodeOS, the installation path of every application is the home directory (or /) followed by the directory lib/node_modules. If the file README.md exists, it saves its content inside the variable readme. Otherwise, it shows an error and exits the process.

// Create a screen object.
var screen = blessed.screen();

var box = blessed.box({
  content: readme,
  alwaysScroll:true,
  scrollable: true,
});

// Append our box to the screen.
screen.append(box);

Blessed has a really simple API; showing the content of a file is as easy as telling it to create a box and loading the content.

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

Now, let’s create a way to exit the man application. We combine the keys escape, q or the emacs-style combination C-c to exit the process.

screen.key(['space','f','j','n'], function(ch, key) {
  box.scroll(box.height);
  screen.render();
});

screen.key(['down'], function(ch, key) {
  box.scroll(1);
  screen.render();
});

screen.key(['up'], function(ch, key) {
  box.scroll(-1);
  screen.render();
});

screen.key(['b','k','p'], function(ch, key) {
  box.scroll(-box.height);
  screen.render();
});

We use the directional keys to scroll up or down one row and the keys space, f, j or n to scroll down a page (as many lines as there are on the screen). Use b, k or p to do the reverse.

box.focus();
screen.render();

Finally, we tell the application to focus on the box we created and render the whole thing. Let’s put those files in the directory /lib/node_modules/bin-man and let’s add a simple README.md, something like this:

# Man

Author: @groundwater

## Install

npkg install bin-man

## Usage

```
Usage: man PKGNAME

Display a packages README.md file
```

We are almost done with our first custom application for NodeOS. Only one last small step remains; we need to create a config file since it is a requirement for NodeOS applications. It is as simple as creating a file in the path /etc/bin-man/config.json with the following content: {}, an empty JSON object. Now, we can try our new application. Running man inside the NodeOS shell should show the readme file we created earlier.

结语

通过上面的示例,我们可以看到在NodeOS实现任何功能都是非常简单的事情,你只需要熟悉Node.js就足够了。

NodeOS拥有非常巨大的发展潜力,我相信它必然会发展成一个伟大的操作系统。当然,里面还有很多功能我们需要支持和完善,但是作为Node.js整个生态系统中很重要的一员,我相信NodeOS很快就会流行起来。如果您有不同看法的话,请在评论上给出来一块探讨。

注:更多文章请关注公众号:techgogogo或个人博客http://techgogogo.com。当然,也非常欢迎您直接微信(zhubaitian1)勾搭。本文由天地会珠海分舵编译自Toptal。转载请自觉。

喜欢 0

这篇文章有1条评论

  1. loo588 2016/9/25 #1 [REPLY]

    hey,这篇文章内容本人认为非常有意思,敢问博主可以让我转载吗?我会保留原文来由的链接以及你的姓名。

发表评论