基于JavaScript的操作系统你听说过吗?


Posted in Javascript onJanuary 28, 2016

我想大多数人听说过 Node.js,但是你听说过 NodeOS 吗?没错,NodeOS,一个用 Node.js 写的操作系统。好吧,实话说,NodeOS 用 Linux 内核来处理各种底层任务,比如硬件通讯什么的,但是除此之外,使用的都是 Node.js。NodeOS 的开发始于两年前,创建者的目的很简单,他只是好奇,“是否有可能仅使用 Node.js 创建一个操作系统呢?”

基于JavaScript的操作系统你听说过吗?

是否有可能仅使用 Node.js 创建一个操作系统呢?

这个主意怎么样?

我们已经看到了 Node.js 在这几年已经取得如此迅猛的发展,那么我们为何不让它更酷一些呢?比如用它做个操作系统。

用户自主的独立文件系统

NodeOS 引入了一个有趣的特性:所有的用户都有一个独立的文件系统,他们在一个简单的文件系统中完成各种工作。因为他们的“主目录”事实上就是他们自己的文件系统 的根(root),所以他们可以不需要任何超级权限就可以将软件包安装到系统中,也不需要配置什么,因为软件包默认就安装在他们自己的主目录里面。此外, 这样也提供了良好的安全性,如果黑客攻入到了某个账户,那么只能访问到该用户所在的部分,最终的结果就是黑客并不能由此影响到整个系统。

Node.js 和NPM

你可以想想,如果一个操作系统使用 Node.js,那就意味着所有在 NPM 中可用的包同时也都是 NodeOS 的软件包。在写作本文时,已经有了超过 21 万的软件包,而且每分每秒都在不断增长。如果几年以后,NodeOS 有了一百万应用,那也没什么好奇怪的。

基于Linux 内核

这看起来并不算什么,Linux 是大多数服务器所采用的操作系统。因为 NodeOS 是基于 Linux 内核的,所以你只需要很少的修改就可以使用那些给其它的 Linux 发行版开发的应用了。

不好的消息

我非常希望 NodeOS 是一个已经完成的作品,但是,它现在还不是。它仍然缺少一些服务器操作系统所必需的关键功能。比如,缺失完整的 BASH 工具集,包括 ps、tail、nano 和 grep 等都没有。更糟糕的是,你也不能把它当成桌面操作系统使用,因为它没有 GUI。当然,你可以实现一些缺失的功能,只需要使用一点点 JavaScript,但是默认情况下,这些功能现在都还没有,真糟糕。

好吧,那我可以试试 NodeOS 吗?

使用 Docker 来体验
最容易、最快捷的体验 NodeOS 的方法如下:

1、一台运行 Mac OSX 或 Linux 计算机,也许 Windows 也可以,但是我没试过。
2、Docker。
当你安装好 Docker 之后,运行一个 NodeOS 实例是很容易的。你只需要执行如下命令就可以了, Docker 会为你完成这魔法般的一切:

sudo docker run -t -i nodeos/nodeos

基于JavaScript的操作系统你听说过吗?

最容易、最快捷的体验 NodeOS 的方法是通过 Docker。

当你运行了上述命令,Docker 会自动从仓库下载 NodeOS 的镜像,并将其安装到一个虚拟环境中。安装好之后,会打开一个连接到 NodeOS 的 SSH 会话。

不用 docker 呢?
有些情况下你也许不能使用 Docker 来体验,或者是你想体验一下最新版本的 NodeOS 。在写作本文时,NodeOS 的镜像已经是两个月前生成的了,而开发版本则是六天前更新的。所以,如果你希望使用最新版本,你应该从源代码开始。这也不算很难,但是要花费一些时间。你 需要:

1、一台运行 Linux 的计算机。你可以在 OS X 上编译它,但是跨平台编译需要花费很多时间,对于 Windows 也如此。
2、Linux 编译构建相关的工具(make、g++、gcc、autoconf)。
3、Qemu。
4、时间,真的需要很多。
如果万事俱备,你就可以从源代码开始编译了:

1、使用下列命令编译: cd NodeOS 并 npm install。
2、我逐字引用了其官方文档的话:“拿上爆米花去看场电影吧,不开玩笑,真的。”,是的,它需要很多时间,做些有意思的事情去吧。
3、执行 bash npm start 来在 Qemu 中运行 NodeOS。
可以工作了吗?
当安装完成后,我们可以通过在 NodeOS 的 shell 中执行  ls命令来看看它是否工作了。输出类似如下:

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

如果显示如上,说明一些基本的命令可以工作了。但是如果我们想要知道网卡地址呢?在 Linux 下,这个命令是  ifconfig ,让我们试试:

command not found: ifconfig

看起来没有 ifconfig 命令。这是因为 NodeOS 默认没有  ifconfig命令。现在怎么办?很简单,NodeOS 有一个集成的包管理器(类似 apt 或 yum) ,叫做 npkg,它是基于 Node 的 NPM 的,很容易使用。可以通过如下命令很方便的安装 ifconfig :

npkg install bin-ifconfig

如果一切正常, ifconfig 命令现在就可以在 shell 中使用了。我们再次试着执行一下,输出类似如下:(我替换了其中的 MAC 地址):

eth0: flags=8863 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
 media: autoselect
 status: active

如果你的输出也类似如上,那说明它可以工作了。你已经成功地安装了你的第一个 NodeOS 应用: ifconfig。

它是可以工作了,然而我们可以用这个操作系统做什么呢?

如果我们只能拿这个用 Node.js 写的操作系统做到你在 Ubuntu 或其它 Linux 发行版上一样的(或更少的)事情,那它有什么价值?其实,整个事情中最有趣的地方是所有的东西都是 Node.js 开发的。这意味着我们可以只需要使用 Node.js 就可以开发我们的应用了。比如,NodeOS 里没有默认实现的 man 命令,它用于显示其它命令的帮助信息。不用担心,实现它很简单。

基于JavaScript的操作系统你听说过吗?

使用 Node.js 构建一个 NodeOS 应用

首先让我们来安装一个叫做 Hipster 的文本编辑器,以便我们可以创建和编辑文件。执行如下命令: npm install -g hipster@0.15.0。这个文本编辑器很简单,除了用作文本编辑之外啥也干不了,不过对于我们来说足够了。

用 Hipster 创建文件很简单,运行 hip filename即可,如: hip package.json。要保存文件请按下 Ctrl + s ,退出按下 Ctrl + q。

在这里,我们使用了一个 NodeOS 的主开发人员所开发的代码,我自己并没有真的去开发这个应用。我们例子中的原始代码可以在 node-bin-man Git 仓库中找到。

让我们回过头来创建我们的第一个 NodeOS 应用。像每个 Node.js 应用(或 NPM 包)一样,我们从创建一个 package.json 文件开始,内容如下:

{
 "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"
 }
}

这些参数 name、version、 author、 repository、 license和 description 是其意自明的。这个 bin 集合是一个 JSON 的键值对对象,包含了命令名及其关联的 JavaScript 文件。在我们的例子中, man 命令关联到  man.js文件。而  dependencies集合包含了这个应用所需要的 NPM 包的列表。在我们的例子中,代码的作者包含了 Blessed 包,这是一个类 curses 的库,可以让 Node.js 支持高级终端界面的 API。

现在我们进入了主要的部分,实际的代码。

#!/usr/bin/env node

这个部分叫做释伴(shebang)。NodeOS 实际上并不需要它,但是它用于告诉操作系统如何执行下面的代码。在这里的意思是,它告诉系统下面的每行代码都需要通过  /usr/bin/env node命令来解释执行。

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

像在 Node.js 中一样, require() 函数加载选定的包到内存中,并将其保存为特定的变量。

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

man 命令的标准行为是如果没有指定要查看的命令时,就显示它自己的帮助信息。在我们的代码示例中也一样:如果没有给出第二个参数(第一个参数是 man 本身),那么该参数的默认值是 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);
}

在这里,程序检查给定的应用是否有一个 readme 文件。在 NodeOS 中,每个应用的安装路径是其主目录(/)下的 lib/node_modules。如果 README.md 文件存在,就将其内容保存到 readme变量中。否则,显示一个错误信息并退出。

// 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 有一个非常简单的 API,要显示一个文件的内容很容易,只需要创建一个  box ,然后载入内容即可。

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

现在,让我们找个退出  man 应用的方法。我们组合了  escape、 q 或 emacs 风格的 C-c 来退出应用。

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();
});

我们使用方向键来上滚和下滚,用 space、 f、 j 或 n 向下翻页,b、 k 或 p 向上翻页。

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

最后,我们让应用将输入焦点放到  box ,我们在这里创建和渲染所有内容。

把上面编辑的这个文件存放到  /lib/node_modules/bin-man 目录下(名字是 man.js),并加一个简单的  README.md ,类似如下:

# Man

Author: @groundwater

## Install

npkg install bin-man

## Usage

```
Usage: man PKGNAME

Display a packages README.md file
```

我们已经基本完成了我们的第一个 NodeOS 定制应用。最后剩下一小步了,我们需要创建一个 NodeOS 应用需要的配置文件。很简单,把它创建到 /etc/bin-man/config.json ,内容只是一个空的 JSON 对象: {}。

现在我们可以试试我们的新应用了。在 NodeOS 中运行 man ,它将展示我们之前创建的 readme 文件。

总结

如你所见,在 NodeOS 中实现任何东西都很简单,你只需要懂得 Node.js 即可。

NodeOS 很有潜力,我认为当实现了更多的功能之后它会成为一个伟大的操作系统。目前仍然需要很多工作,但是在整个Node.js 生态系统兴盛发展的形势下,万一哪天它很快地成为一个流行的操作系统也没什么好惊奇的。

Javascript 相关文章推荐
JavaScript CSS修改学习第二章 样式
Feb 19 Javascript
javascript中的new使用
Mar 20 Javascript
ExtJS TabPanel beforeremove beforeclose使用说明
Mar 31 Javascript
javascript使用eval或者new Function进行语法检查
Oct 16 Javascript
JavaScript 基础篇之对象、数组使用介绍(三)
Apr 07 Javascript
js中settimeout方法加参数
Feb 28 Javascript
JS不完全国际化&本地化手册 之 理论篇
Sep 27 Javascript
jQuery实现文档树效果
Feb 20 Javascript
JS正则表达式判断有效数实例代码
Mar 13 Javascript
解决IOS端微信H5页面软键盘弹起后页面下方留白的问题
Jun 05 Javascript
Vue3 源码导读(推荐)
Oct 14 Javascript
JavaScript中变量提升机制示例详解
Dec 27 Javascript
js+canvas绘制矩形的方法
Jan 28 #Javascript
js+canvas简单绘制圆圈的方法
Jan 28 #Javascript
谈一谈javascript闭包
Jan 28 #Javascript
JavaScript统计字符串中每个字符出现次数完整实例
Jan 28 #Javascript
基于javascript实现checkbox复选框实例代码
Jan 28 #Javascript
JavaScript黑洞数字之运算路线查找算法(递归算法)实例
Jan 28 #Javascript
JS+CSS实现DIV层的展开、收缩效果
Jan 28 #Javascript
You might like
php 静态化实现代码
2009/03/20 PHP
PHP获取当前完整URL地址的函数
2014/12/21 PHP
浅谈PHP接收POST数据方式
2015/06/05 PHP
用javascript动态调整iframe高度的方法
2007/03/06 Javascript
javascript高级学习笔记整理
2011/08/14 Javascript
js 获取(接收)地址栏参数值的方法
2013/04/01 Javascript
js实现数组去重、判断数组以及对象中的内容是否相同
2013/11/29 Javascript
JavaScript中使用Callback控制流程介绍
2015/03/16 Javascript
vue双向数据绑定原理探究(附demo)
2017/01/17 Javascript
微信小程序滚动Tab实现左右可滑动切换
2017/08/17 Javascript
vue.js  父向子组件传参的实例代码
2017/10/29 Javascript
写给小白看的JavaScript异步
2017/11/29 Javascript
ExtJs整合Echarts的示例代码
2018/02/27 Javascript
AngularJS模态框模板ngDialog的使用详解
2018/05/11 Javascript
微信小程序授权登录及解密unionId出错的方法
2018/09/26 Javascript
Vue axios 将传递的json数据转为form data的例子
2019/10/29 Javascript
Node绑定全局TraceID的实现方法
2019/11/14 Javascript
Vue实现Header渐隐渐现效果的实例代码
2020/11/05 Javascript
Python实现线程池代码分享
2015/06/21 Python
安装Python的教程-Windows
2017/07/22 Python
Python中那些 Pythonic的写法详解
2019/07/02 Python
python Elasticsearch索引建立和数据的上传详解
2019/08/04 Python
python隐藏类中属性的3种实现方法
2019/12/19 Python
利用python实现凯撒密码加解密功能
2020/03/31 Python
Python 执行矩阵与线性代数运算
2020/08/01 Python
安装pyecharts1.8.0版本后导入pyecharts模块绘图时报错: “所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 ”的解决方法
2020/08/18 Python
Python调用JavaScript代码的方法
2020/10/27 Python
HTML5边玩边学(1)画布实现方法
2010/09/21 HTML / CSS
Html5插件教程之添加浏览器放大镜效果的商品橱窗
2016/01/07 HTML / CSS
奥地利时尚、美容、玩具和家居之家:Kastner & Öhler
2020/04/26 全球购物
结构和类有什么异同
2012/07/16 面试题
小学生班会演讲稿
2014/01/09 职场文书
挖掘机司机岗位职责
2014/02/12 职场文书
详细的本科生职业生涯规划范文
2014/09/16 职场文书
2015年大学生暑期实习报告
2015/07/13 职场文书
Python数据类型最全知识总结
2021/05/31 Python