Skip to content

Instantly share code, notes, and snippets.

@monsat
Last active December 11, 2015 08:08
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save monsat/4571063 to your computer and use it in GitHub Desktop.
Save monsat/4571063 to your computer and use it in GitHub Desktop.

neu.Node

概要

neu.Node(ノイノード)は、iOS デバイス用に Node.js 互換の API を実装したもので、これにより、アプリケーション開発者はさまざまな小さなサーバ(httpサーバ、チャットサーバ、プロキシサーバ、ゲームサーバ等)を自分の iOS アプリケーションの中に埋め込むことができるようになります。

neu.Node を使えば、iOS デバイスは単なる『クライアント』デバイスではなくなります。 デバイスはそれぞれネットワークの『ノード』となり、 分散コンピューティングのサービス の提供や、ユーザ・エクスペリエンスの向上に大きく貢献することになるのです。

neu.Node は今までに無いタイプのアプリケーションを可能にします。たとえば:

  • サーバを使用しない複数プレイヤー用のゲーム
  • アドホックまたはローカルのソーシャル・ネットワーク・アプリケーション
  • P2Pファイル共有、共同制作、コラボレーション
  • リアルタイムなメディア転送(例えば、セキュリティカメラなど)
  • より高度なキャッシングとオフラインをサポートした、埋め込みプロキシサーバーでのHTML5アプリ

ライセンス

すべてのコードは、 MIT License の下でライセンスされています。

サポートとコミュニティ

Facebookの neu.Node グループ に参加してください。

Node.js と neu.Node

neu.Node は、Node.js を単に iOS に移植したものではありません。 iOS にはそのまま Node.js を実行するには、あまりに多くの制限があるのです。

iOS 上では、アプリケーションが動的に生成したコードを実行することはできないので、V8 のジャストインタイムコンパイルは使えません。

iOS 上では、Node.js の実装に使用している、アプリケーションのファイルシステムやプロセス等の低レベルのシステムリソースへのアクセスが許されていません。

また、携帯端末のパフォーマンス特性は(もともと Node.js が想定している)サーバとはかなり異なっています。携帯端末においては、消費電力とメモリの使用量により多くの注意を払う必要があり、Node.js に使用されているいくつかのテクニック(例えば、スレッドプーリングとインメモリキャッシュなど)は携帯端末には適していません。

設計原理とアーキテクチャ

このプロジェクトの主なゴールは「開発者が iOS デバイス上で軽量サーバを実行するための Node.js 互換開発環境を提供すること」です。

Node.js との互換性があることは非常に重要ですが、全体的な互換は必要ありません。neu.Node は、組み込みサーバを実装するのに不可欠な Node.js API のサブセットを提供します。

neu.Node は Objective-C で実装された libnode.core と、標準の JavaScript ライブラリのセットで構成されています。

neu.Node では UIWebView を(V8 ではなく)JavaScript ランタイムとして使っています。 JavaScript から Objective-C のコードを呼び出したり、Objective-C から JavaScript への非同期イベントを作動させるために必要なカスタム JavaScript / Objective-C(JS/ OC)ブリッジを用意しています。

デバッグ

(JavaScript で記述された)neu.Node をデバッグするためには、以下のことが必要です。

  1. Xcode 上でアプリを実行する。
  2. (Macの)Safari で「開発 -> <デバイス名> -> <アプリ名> 」を選択し、 Web インスペクタを自作のアプリにアタッチする。

iPhone / iPad のアプリケーション設定で、Safari -> 詳細 -> Webインスペクタをオンにする必要があります。

標準のJavaScriptライブラリ

global.js はキーとなる JavaScript のライブラリであり、JS/OC ブリッジや、 require メソッド、 consoleprocess などの組み込みのグローバルも実装されています。

assert.js, events.js, freelist.js, punycode.js, querystring.js, stream.js はいずれの C++ コードにも依存していないので、 Node.js から流用したものです。

dns.js, fs.js, net.js, http.js は、Node.js にある該当モジュールの neu.Node 版の実装です。

static.js と mime.js は、node-static(静的 HTTP サーバ用の人気モジュール)と同等の機能を提供する標準拡張です。HTTP 経由で大きなファイルを効率的に取り扱うメモリマップファイルを使用しています。

グローバル

require(module_name)

モジュールを必要とします。

通常の Node.js とは異なり、すべての必要なモジュールを明示的に ローダーファイル に読み込む必要があります。

loader.html の内容(ローダーファイル):

<html>
<header>
</header>
  <body></body>
  <script src="./global.js"></script>
  <script src="./util.js"></script>
  <script src="./events.js"></script>
  <script src="./punycode.js"></script>
  <script src="./querystring.js"></script>
  <script src="./url.js"></script>
  <script src="./path.js"></script>
  <script src="./stream.js"></script>
  <script src="./assert.js"></script>
  <script src="./freelist.js"></script>
  <script src="./dns.js"></script>
  <script src="./net.js"></script>
  <script src="./http.js"></script>
  <script src="./server.js"></script>
</html>

server.js の内容:

var http = require('http');
var server = http.createServer(handler);
function handler(request, response) {
  ...
}

__dirname

現在実行中のスクリプトがあるディレクトリの名前。

neu.Node 下では、 __ dirname の実際の値は、常にメインバンドルの「ルート」フォルダを示す空の文字列です。

server.js の内容:

var fs = require('fs');
fs.readFile(__dirname + '/myapp/templates.html', 
            'utf8', function(err, str) {
  ...
});

neu.Nodeでは、上記の readFile 関数は、メインバンドルの /root/myapp/ フォルダ内の templates.html にアクセスします。

module, module.exports, exports

module、module.exports と exports にアクセスするには、各モジュールファイルが以下のコードのように記述する(囲まれている)必要があります。

(function() {
  var module = require.register('module_name');
  var exports = module.exports;
  ...
  ... // モジュールの定義
  ...
})();

もしモジュールが neu.Node と Node.js の両方に使われる場合は、代わりに以下のコードのように記述する(囲む)必要があります。

(function(module_) {
  var module = module_ || require.register('module_name');
  var exports = module.exports;
  ...
  ... // モジュールの定義
  ...
})(typeof module != 'undefined' ? module : null);

process (global object)

process.platform

neu.Node では、この関数は 'ios' を返します。

process.nextTick(callback)

neu.Nodeでは、この関数は setTimeout(callback, 0) と同等です。

console (global object)

console.log([data], [...])

neu.Nodeでは、この関数はXcodeのコンソールに出力します。

net module

net.connect(options, [connectListner]), net.createConnection(options, [connectListner])

options で指定された host:port へのTCPソケット接続を作成します。パラメータ connectListner は、 'connect' イベントのリスナーとして追加されます。

  • options.host:ホスト名またはIPアドレスを指定
  • options.port:ポート番号を指定

Class: net.Socket()

Node.jsのように、このオブジェクトは双方向ストリームインタフェースを実装したTCPソケットを抽象化したものです。

net.createServer(connectionListner)

新しいTCPサーバを作成します。引数 connectionListner は自動的に 'connection' イベントのリスナーとして設定されます。

Class: net.Server(connectionListner)

このクラスは、TCPまたはUNIXストリーム型接続サーバーを作成するために使用されます。サーバーは、新しい着信接続を listen できる net.Socket です。

http module

http.STATUS_CODES

標準的な全HTTPレスポンスステータスコードのコレクションと、それぞれの簡単な説明です。

http.createServer(requestListner)

新しい Web サーバのオブジェクトを返します。

requestListener は、自動的に 'request' イベントに追加される関数です。

http.request(options, callback)

options は、オブジェクトまたは文字列を指定できます。文字列である場合、url.parse() で自動的にパースされます。

Options:

  • host: リクエスト発信先サーバのドメイン名または IP アドレス。デフォルト設定は 'localhost'。
  • port: リモートサーバのポート。デフォルトは80。
  • method: HTTP リクエストメソッドを指定する文字列。デフォルトは 'GET'。
  • headers: リクエストヘッダを含むオブジェクト。
  • path: リクエストパス。デフォルトは '/'。クエリ文字列がある場合は含める必要があります。例: '/index.html?page=12'

fs module

fs.readFile(filename, encoding, callback)

非同期的にファイルの内容全体を読み取ります。引数 encoding を 'utf8' に指定する必要があります。

ファイル名が '/_doc/' で始まる場合は、Document ディレクトリ内のファイルにアクセスします。 ファイル名が '/_prv/' で始まる場合は、Library ディレクトリ内のファイルにアクセスします。 それ以外の場合は、メインバンドルの ’root' ディレクトリ内のファイルにアクセスします。

fs.writeFile(filename, data, encoding, callback)

非同期的にデータをファイルに書き込みます。既存のファイルがある場合は上書きされます。データは文字列である必要があります(Node.js とは異なり、バッファであってはなりません)。

常に Library ディレクトリの 作業ディレクトリ ('app' フォルダ)にファイルを書き込みます。

dns module

dns.resolve4(domain, callback)

ドメイン(例: 'google.com')を解決しIPv4 アドレスの配列を返します。

このコー​​ルバックは引数(err、addresses)を持っています。

libnode.core

libnode.core は、Objective-C で実装された静的ライブラリです。

NodeController クラス

libnode.core のプライマリインターフェースは NodeController クラスです:

@interface NodeController : UIViewController {
  IBOutlet UIBarButtonItem* _btnPlay, *_btnStop;
}
@property (nonatomic, strong) NSURL* url;
@property (nonatomic) BOOL autoStart;
@property (nonatomic, strong) NSDictionary* appInfo;
-(IBAction) play:(id)sender;
-(IBAction) stop:(id)sender;
-(NSArray*) allServers;
@end
  • url プロパティは loader HTML ファイルの位置を指定します。
  • autostart プロパティは、ビューが表示された際にサーバが自動的に起動するかどうかを指定します。
  • appInfo 作業ディレクトリ名を指定します(Library ディレクトリ以下)。
  • play: メソッドでサーバを起動します。
  • stop: メソッドでサーバを停止します。
  • allServer メソッドは インスタンスの配列です。

アプリケーションは NodeControllerのインスタンスを作成し、ビューをビュー階層に追加し(実際に表示されている必要はありません)、play: メソッドを呼び出す(またはビューをビュー階層に追加する前に autoStart プロパティをセットする)必要があります。

NodeService プロトコル

NodeService は、neu.Node アプリケーションが提供する net または http サービスを定義するプロトコルです。

@protocol NodeService <NSObject>
@property (nonatomic, readonly) NSString* url;
@property (nonatomic, readonly) NSString* protocol;
@property (nonatomic, readonly) NSUInteger port;
@property (nonatomic, readonly) NSUInteger connections; 
@property (nonatomic, readonly) NSMutableDictionary* extra; // extra storage
@property (nonatomic, strong) NSNetService* service; // bonjour
@end
  • url サービスの URL を指定(例えば 'http://10.0.1.2:8000' )
  • protocol プロトコルを指定('http' または 'net')
  • port このサービスに割当てられたポート番号を指定
  • connections 現在の接続数を示す
  • extra アプリケーション固有のインメモリストレージ
  • service bonjour 用の NSNetService オブジェクトインスタンス(将来の拡張用)
@snakajima
Copy link

翻訳、ありがとうございます。細かな部分ですが、

>iOS は本来 V8 のジャストインタイムコンパイルを禁止しているため、アプリケーションが動的に生成したコードを実行することはできません。
iOS は、Node.js が得意とする、アプリケーションのファイルシステムやプロセス等の低レベルのシステムリソースへのアクセスを許しません。

は、

iOS 上では、アプリケーションが動的に生成したコードを実行することはできないので、V8 のジャストインタイムコンパイルは使えません。
iOS 上では、Node.js の実装に使用している、アプリケーションのファイルシステムやプロセス等の低レベルのシステムリソースへのアクセスが許されていません。

の方が良いと思います。

@monsat
Copy link
Author

monsat commented Jan 20, 2013

ありがとうございます!早速修正します! 👍

@monsat
Copy link
Author

monsat commented Jan 20, 2013

こちらのドキュメントの原文は
https://github.com/snakajima/neunode/blob/master/README.md
となります。

(snakajima/neunode@c8bed61#README.md)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment