Nodeクックブックを読む

6 4月

Nodeクックブックを読んでいます。本が書かれたときとは,モジュール等のバージョンが異なってそのままでは動かないところがありました。他にもでてきそうなのでメモにして残します。node や npm の知識がそもそもないので、本のままのコードが動かないとなると苦労しそうです。node のバージョンは 6.9.5 です。

p36あたり
connect のバージョンが変化したようです。自分の環境ではまず connect をインストールすることから始めました。ソースのあるフォルダーに移動して、package.json を作るところからですが、npm init と打ち込んであとは enter を連打します。

friend@xpython:~/scripts/2/2.1.1$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install  --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (2.1.1) 
version: (1.0.0) 
description: 
entry point: (server.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /home/friend/scripts/2/2.1.1/package.json:

{
  "name": "2.1.1",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) 

これで、package.json が現在のフォルダーに作られました。ここで npm install connect とやると入ることは入るのですが、node server.js と打ち込んだ時に、下記のようなエラーが出ます。

friend@xpython:~/scripts/2/2.1.1$ npm install connect
2.1.1@1.0.0 /home/friend/scripts/2/2.1.1
└─┬ connect@3.6.6 
  ├─┬ debug@2.6.9 
  │ └── ms@2.0.0 
  ├─┬ finalhandler@1.1.0 
  │ ├── encodeurl@1.0.2 
  │ ├── escape-html@1.0.3 
  │ ├─┬ on-finished@2.3.0 
  │ │ └── ee-first@1.1.1 
  │ ├── statuses@1.3.1 
  │ └── unpipe@1.0.0 
  ├── parseurl@1.3.2 
  └── utils-merge@1.0.1 

npm WARN 2.1.1@1.0.0 No description
npm WARN 2.1.1@1.0.0 No repository field.
friend@xpython:~/scripts/2/2.1.1$ node server.js 
/home/friend/scripts/2/2.1.1/server.js:6
	.use(connect.bodyParser())
	             ^

TypeError: connect.bodyParser is not a function
    at Object. (/home/friend/scripts/2/2.1.1/server.js:6:15)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3

connect.bodyParser がファンクションでないと言われてしまいます。connect に関して調べると、バージョンがあがって動かなくなる等の記事がありました。それでいったん作成したファイルを削除して作り直しました。今度の connect のインストールはバージョンを指定します。

friend@xpython:~/scripts/2/2.1.1$ npm install connect@2.6.1
npm WARN deprecated connect@2.6.1: connect 2.x series is deprecated
2.1.1@1.0.0 /home/friend/scripts/2/2.1.1
└─┬ connect@2.6.1 
  ├── bytes@0.1.0 
  ├── cookie@0.0.4 
  ├── cookie-signature@0.0.1 
  ├── crc@0.2.0 
  ├─┬ debug@3.1.0 
  │ └── ms@2.0.0 
  ├── formidable@1.0.11 
  ├── fresh@0.1.0 
  ├── pause@0.0.1 
  ├── qs@0.5.1 
  └─┬ send@0.1.0 
    ├── mime@1.2.6 
    └── range-parser@0.0.4 

npm WARN 2.1.1@1.0.0 No description
npm WARN 2.1.1@1.0.0 No repository field.

これで動きました。

p38 あたり
レシピ 2.2 ですが、 formidable 1.0.11 を利用しても動きません。

friend@xpython:~/scripts/2/2.2$ node server.js 
{ host: '192.168.100.18:8080',
  'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'accept-language': 'ja,en-US;q=0.7,en;q=0.3',
  'accept-encoding': 'gzip, deflate',
  referer: 'http://192.168.100.18:8080/',
  'content-type': 'multipart/form-data; boundary=---------------------------22430255711803',
  'content-length': '70525',
  cookie: 'io=cZZnNBSJM6tV7cEVAAAF',
  connection: 'keep-alive',
  'upgrade-insecure-requests': '1' }
buffer.js:732
    throw new Error('Buffer.write(string, encoding, offset[, length]) ' +
    ^

Error: Buffer.write(string, encoding, offset[, length]) is no longer supported
    at Buffer.write (buffer.js:732:11)
    at MultipartParser.initWithBoundary (/home/friend/scripts/2/2.2/node_modules/formidable/lib/multipart_parser.js:66:17)
    at IncomingForm._initMultipart (/home/friend/scripts/2/2.2/node_modules/formidable/lib/incoming_form.js:272:10)
    at IncomingForm._parseContentType (/home/friend/scripts/2/2.2/node_modules/formidable/lib/incoming_form.js:231:12)
    at IncomingForm.writeHeaders (/home/friend/scripts/2/2.2/node_modules/formidable/lib/incoming_form.js:131:8)
    at IncomingForm.parse (/home/friend/scripts/2/2.2/node_modules/formidable/lib/incoming_form.js:84:8)
    at Server. (/home/friend/scripts/2/2.2/server.js:22:12)
    at emitTwo (events.js:106:13)
    at Server.emit (events.js:191:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:546:12)

Buffer.write(string, encoding, offset[, length]) is no longer supported と言われてしまいます。ここにあったのですが node_modules/formidable/lib/multipart_parser.js の61行と62行を下記のように書き換えます。

this.boundary.write('\r\n--', 0, 'ascii');
this.boundary.write(str, 4, 'ascii');

引数が入れ替わったのでしょうか?
このようにすると、uploads フォルダーにファイルが保存されます。受け取った時のコンソールの出力です。

friend@xpython:~/scripts/2/2.2$ node server.js 
{ host: '192.168.100.18:8080',
  'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'accept-language': 'ja,en-US;q=0.7,en;q=0.3',
  'accept-encoding': 'gzip, deflate',
  referer: 'http://192.168.100.18:8080/',
  'content-type': 'multipart/form-data; boundary=---------------------------15362245056078',
  'content-length': '70525',
  cookie: 'io=cZZnNBSJM6tV7cEVAAAF',
  connection: 'keep-alive',
  'upgrade-insecure-requests': '1' }
File {
  domain: null,
  _events: {},
  _eventsCount: 0,
  _maxListeners: undefined,
  size: 0,
  path: 'uploads/0e44a26b4cf7f9ca9cc5171eb34c5136',
  name: '',
  type: 'application/octet-stream',
  hash: false,
  lastModifiedDate: null,
  _writeStream: 
   WriteStream {
     _writableState: 
      WritableState {
        objectMode: false,
        highWaterMark: 16384,
        needDrain: false,
        ending: true,
        ended: true,
        finished: true,
        decodeStrings: true,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        corked: 0,
        sync: true,
        bufferProcessing: false,
        onwrite: [Function],
        writecb: null,
        writelen: 0,
        bufferedRequest: null,
        lastBufferedRequest: null,
        pendingcb: 0,
        prefinished: true,
        errorEmitted: false,
        bufferedRequestCount: 0,
        corkedRequestsFree: [Object] },
     writable: false,
     domain: null,
     _events: { open: [Object] },
     _eventsCount: 1,
     _maxListeners: undefined,
     path: 'uploads/0e44a26b4cf7f9ca9cc5171eb34c5136',
     fd: null,
     flags: 'w',
     mode: 438,
     start: undefined,
     autoClose: true,
     pos: undefined,
     bytesWritten: 0 },
  length: [Getter],
  filename: [Getter],
  mime: [Getter] }
File {
  domain: null,
  _events: {},
  _eventsCount: 0,
  _maxListeners: undefined,
  size: 70180,
  path: 'uploads/652a5c26aef2ad639f04ca5fc40df784',
  name: '����2.png',
  type: 'image/png',
  hash: false,
  lastModifiedDate: 2018-04-06T08:42:59.915Z,
  _writeStream: 
   WriteStream {
     _writableState: 
      WritableState {
        objectMode: false,
        highWaterMark: 16384,
        needDrain: false,
        ending: true,
        ended: true,
        finished: true,
        decodeStrings: true,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        corked: 0,
        sync: false,
        bufferProcessing: false,
        onwrite: [Function],
        writecb: null,
        writelen: 0,
        bufferedRequest: null,
        lastBufferedRequest: null,
        pendingcb: 0,
        prefinished: true,
        errorEmitted: false,
        bufferedRequestCount: 0,
        corkedRequestsFree: [Object] },
     writable: false,
     domain: null,
     _events: {},
     _eventsCount: 0,
     _maxListeners: undefined,
     path: 'uploads/652a5c26aef2ad639f04ca5fc40df784',
     fd: null,
     flags: 'w',
     mode: 438,
     start: undefined,
     autoClose: true,
     pos: undefined,
     bytesWritten: 70180,
     closed: true },
  length: [Getter],
  filename: [Getter],
  mime: [Getter] }
end

3.1.1 p62 あたり

「client.html ファイルをブラウザで開くと」とあります。これは WEB サーバー 上にあるサイト: http://localhost:8080/client.html を開くのではなくて,ローカルファイルをダブルクリックして表示させるという話です。例えば、file:///home/friend/scripts/3/3.1.1/client.html などと URL 表示はなります。

3.2 p63 あたり
下記のようなコードがあります。

var isTxt = (obj[key] && {}.toString.call(obj[key]) !== '[object Object]');

まず {} が Object の代わりだと思うのですが、正しいのかな。
例えば obj[key] の内容が { name: 'Ryan Dahl', irc: 'ryah', twitter: 'ryah', github: [ 'ry', joyent' ], location: 'San Francisco, USA', description: 'Creator of node.js' } という感じのオブジェクトであるとして、そうすると {}.toString.call(obj[key])[object Object] となるわけですが、これらのアンドをとると得られるものは [object Object] です。1 か 0 ではありません(常識なのか)。参考サイトによると、前の項 を false と見ることができる場合は、前の項 を返す。そうでない場合は、後ろの項 を返す様です。

3.3 p73 あたり

ここは jQuery で書かれたコードに $.get('http://localhost:8080/ . . . とあって,サーバーを起動したマシン上のブラウザで開くことが前提となっています。しかし,それをサーバーの URL に書き換えたら他からのアクセスでも上手く動きました。

3.4 p83 あたり
npm install colors@0.6.0 で colors をインストールして、動かしてみると下記のようなエラーとなりました。

friend@xpython:~/scripts/3/3.4$ node twitter_trends.js 
_http_outgoing.js:358
    throw new TypeError('The header content contains invalid characters');
    ^

TypeError: The header content contains invalid characters
    at ClientRequest.OutgoingMessage.setHeader (_http_outgoing.js:358:11)
    at new ClientRequest (_http_client.js:86:14)
    at Object.exports.request (http.js:31:10)
    at Object.exports.get (http.js:35:21)
    at makeCall (/home/friend/scripts/3/3.4/twitter_trends.js:5:7)
    at Object. (/home/friend/scripts/3/3.4/twitter_trends.js:52:1)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)

良く分かりませんが、コードにある日本語(トレンド)を英語(trend)に変換しました。いくらか動き出しました。出力は長過ぎるので全部は載せません。最後にエラーが出ました。

friend@xpython:~/scripts/3/3.4$ node twitter_trends.js 
IncomingMessage {
  _readableState: 
   ReadableState {
     objectMode: false,
     highWaterMark: 16384,
     buffer: BufferList { head: null, tail: null, length: 0 },
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: null,
     ended: false,
     endEmitted: false,
     reading: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     resumeScheduled: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: true,
     decoder: null,
     encoding: null },
  readable: true,
  domain: null,
  _events: { end: [Function: responseOnEnd] },
  _eventsCount: 1,
  _maxListeners: undefined,

途中略

     _header: 'GET /1/trends/1.json HTTP/1.1\r\nUser-Agent: Node Cookbook: Twitter trend\r\nHost: api.twitter.com\r\nConnection: close\r\n\r\n',
     _headers: 
      { 'user-agent': 'Node Cookbook: Twitter trend',
        host: 'api.twitter.com' },
     _headerNames: { 'user-agent': 'User-Agent', host: 'Host' },
     _onPendingData: null,
     agent: 
      Agent {
        domain: null,
        _events: [Object],
        _eventsCount: 1,
        _maxListeners: undefined,
        defaultPort: 80,
        protocol: 'http:',
        options: [Object],
        requests: {},
        sockets: [Object],
        freeSockets: {},
        keepAliveMsecs: 1000,
        keepAlive: false,
        maxSockets: Infinity,
        maxFreeSockets: 256 },
     socketPath: undefined,
     timeout: undefined,
     method: 'GET',
     path: '/1/trends/1.json',
     _ended: false,
     parser: 
      HTTPParser {
        '0': [Function: parserOnHeaders],
        '1': [Function: parserOnHeadersComplete],
        '2': [Function: parserOnBody],
        '3': [Function: parserOnMessageComplete],
        '4': null,
        _headers: [],
        _url: '',
        _consumed: false,
        socket: [Object],
        incoming: [Circular],
        outgoing: [Circular],
        maxHeaderPairs: 2000,
        onIncoming: [Function: parserOnIncomingClient] },
     res: [Circular] } }

/home/friend/scripts/3/3.4/twitter_trends.js:42
			throw('サーバがエラーを返しました。エラーコード:' + res.statusCode);
			^
サーバがエラーを返しました。エラーコード:403
friend@xpython:~/scripts/3/3.4$ 

403 はアクセスが禁止されている場合です(forbidden)。search.twitter.com にアクセスすると https://twitter.com/search-home に飛ばされます。古い記事を参考にして http://search.twitter.com/search.json?q=java のようなサーチをかけてみると、

{"errors":[{"message":"The Twitter REST API v1 is no longer active. Please migrate to API v1.1. https://dev.twitter.com/docs/api/1.1/overview.","code":64}]}

こんな感じの返事が来ます。API の変更や、https に変わっていることもあって、かなりコードを書き換える必要があるみたいです。何回か実行すると返事も返らなくなって、ただ 403 が返るだけになりました。ここは諦めましょう。3.4.1 も動かせません。

4.2 p96あたり
mysql のバージョンを 0.9.6 と指定してインストールしても動かない。下記のように、接続から上手くいっていない様子。

friend@xpython:~/scripts/4/4.2$ node mysql.js 
events.js:160
      throw er; // Unhandled 'error' event
      ^

Error: Access denied for user 'root'@'localhost' (using password: YES)
    at Function.Client._packetToUserObject (/home/friend/scripts/4/4.2/node_modules/mysql/lib/client.js:394:7)
    at Client._handlePacket (/home/friend/scripts/4/4.2/node_modules/mysql/lib/client.js:307:43)
    at emitOne (events.js:96:13)
    at Parser.emit (events.js:188:7)
    at emitPacket (/home/friend/scripts/4/4.2/node_modules/mysql/lib/parser.js:71:14)
    at Parser.write (/home/friend/scripts/4/4.2/node_modules/mysql/lib/parser.js:576:7)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:176:18)
    at Socket.Readable.push (_stream_readable.js:134:10)

しかたがないので、新しい mysql をインストールした(2.15.0)。接続から異なるようだ。同じフォルダーにある test.js を多少書き換えて動かしてみた。特にエラーではない書き換えもある。

var mysql = require('mysql');
//var client = mysql.createClient({
//	user: 'root',
//	password: '********'
//});

var client = mysql.createConnection({
	host: 'localhost',
	user: 'root',
	password: '********'
});

//client.query('CREATE DATABASE quotes');

client.query('CREATE DATABASE IF NOT EXISTS quotes');

//client.useDatabase('quotes');

client.query('USE quotes');


client.query('CREATE TABLE quotes.quotes (' +
	'id INT NOT NULL AUTO_INCREMENT, ' +
	'author VARCHAR(128) NOT NULL, ' +
	'quote TEXT NOT NULL, PRIMARY KEY(id)' +
	')'
);


client.end();

とりあえず、テーブルは作成された。
mysql.js を下記のように書き換えてみました。一応これで動きました。

var mysql = require('mysql');

var client = mysql.createConnection({
	host:'localhost',
	user: 'root',
	password: '********'
});

client.query('CREATE DATABASE IF NOT EXISTS quotes');
client.query('USE quotes');

client.query('CREATE TABLE IF NOT EXISTS quotes.quotes (' +
	'id INT NOT NULL AUTO_INCREMENT, ' +
	'author VARCHAR(128) NOT NULL, ' +
	'quote TEXT NOT NULL, PRIMARY KEY(id)' +
	')'
);


var ignore = [mysql.ERROR_DB_CREATE_EXISTS, mysql.ERROR_TABLE_EXISTS_ERROR];

client.on('error', function(err){
	if(ignore.indexOf(err.number) > -1) { return; }
	throw err;
});

client.query('INSERT INTO quotes.quotes (' +
	'author, quote) ' +
	'VALUES ("kondo", "test words");'
);


client.end();

日本語が通らないので、日本語以外をデータベースに書き込んでみました。エラー処理の記述は変更していませんが、正しいのかどうかは分からない。

4.2.2 p101あたり
最後に表示するところにある on が上手く動作しないので、書き換えた。

var params = {
	author: process.argv[2],
	quote: process.argv[3]
}

var mysql = require('mysql');
var client = mysql.createConnection({
	user: 'root',
	password: '********'
	//debug: 'true'
});

client.query('CREATE DATABASE IF NOT EXISTS quotes');
client.query('USE quotes');

client.query('CREATE TABLE IF NOT EXISTS quotes.quotes (' +
	'id INT NOT NULL AUTO_INCREMENT, ' +
	'author VARCHAR(128) NOT NULL, ' +
	'quote TEXT NOT NULL, PRIMARY KEY(id)' +
	')'
);

var ignore = [mysql.ERROR_DB_CREATE_EXISTS, mysql.ERROR_TABLE_EXISTS_ERROR];

client.on('error', function(err){
	if(ignore.indexOf(err.number) > -1) { return; }
	throw err;
});

if(params.author && params.quote) {
	client.query('INSERT INTO quotes.quotes (' +
	'author, quote) ' +
	'VALUES(?, ?);', [params.author, params.quote]);
}

if(params.author) {
	client.query('SELECT * FROM quotes WHERE ' + 'author LIKE ' + client.escape(params.author), function(err, raws, fields){
		if (err) {
			console.log('err:' + err);
		} else {
			raws.forEach(function(raw){
				console.log('%s: %s', raw.author, raw.quote);
			});
		}

	});
}

client.end();

4.3 p102あたり
mongodb のバージョンを指定して(1.1.7)、インストールしても動かない。

friend@xpython:~/scripts/4/4.3$ node quotes.js 'kondo' 'first'
/home/friend/scripts/4/4.3/node_modules/mongodb/lib/mongodb/db.js:869
      || (selector['mapreduce'] && selector.out = 'inline')) {
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ReferenceError: Invalid left-hand side in assignment
    at Object.exports.runInThisContext (vm.js:76:16)
    at Module._compile (module.js:542:28)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at /home/friend/scripts/4/4.3/node_modules/mongodb/lib/mongodb/index.js:29:17
    at Array.forEach (native)

mongodb のコマンドで確認すると、データベースは作成されているようでした。中身は空ですが。

friend@xpython:~/scripts/4/4.3$ mongo
MongoDB shell version: 2.6.10
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
	http://docs.mongodb.org/
Questions? Try the support group
	http://groups.google.com/group/mongodb-user
> use quates
switched to db quates
> db.quates.find()
> quit()
friend@xpython:~/scripts/4/4.3$ 

mongodb を新しいものに入れ替えます。

friend@xpython:~/scripts/4/4.3$ npm install mongodb
4.3@1.0.0 /home/friend/scripts/4/4.3
└─┬ mongodb@3.0.7 
  └─┬ mongodb-core@3.0.7 
    ├── bson@1.0.6 
    └─┬ require_optional@1.0.1 
      ├── resolve-from@2.0.0 
      └── semver@5.5.0 

npm WARN 4.3@1.0.0 No description
npm WARN 4.3@1.0.0 No repository field.

再び実行すると、今度は下記のようなエラーとなりました。

friend@xpython:~/scripts/4/4.3$ node quotes.js 'kondo' 'first'
/home/friend/scripts/4/4.3/quotes.js:7
client.open(function (err, client) {
       ^

TypeError: client.open is not a function
    at Object. (/home/friend/scripts/4/4.3/quotes.js:7:8)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3

かなりコマンドが変化しているようで、下記のように書き換えてやっと動きました(参考サイト)。server 云々という記述は無くなりました。insertMany で書き込んでいますが、書き込むデータは一個です。

var mongo = require('mongodb');

var mongoClient = mongo.MongoClient;

var params = { author: process.argv[2], quote: process.argv[3] };

mongoClient.connect('mongodb://localhost:27017', function (err, client){
	//console.log(client);
	var quotes = client.db("quotes");
	var collection = quotes.collection('quotes');

	if(params.author && params.quote) {
		collection.insertMany([{ author: params.author, quote: params.quote }], function (err, result) {
			console.log(result);
});
	}

	if(params.author) {
		collection.find({ author: params.author }).each(function(err, doc) {
			if(err) { throw err; }
			if(doc) {
				console.log('%s: %s', doc.author, doc.quote);
				return;
			}
			client.close();
		});
		return;
	}
	client.close();
});

実行結果です。何回か動かして、データベースにすでにいくつかデータが入っています。

friend@xpython:~/scripts/4/4.3$ node quotes.js 'kondo' 'second'
{ result: { ok: 1, n: 1 },
  ops: 
   [ { author: 'kondo',
       quote: 'second',
       _id: 5aeb487c1e3b7826aee844a7 } ],
  insertedCount: 1,
  insertedIds: { '0': 5aeb487c1e3b7826aee844a7 } }
friend@xpython:~/scripts/4/4.3$ node quotes.js 'kondo' 'second'
{ result: { ok: 1, n: 1 },
  ops: 
   [ { author: 'kondo',
       quote: 'second',
       _id: 5aeb495e458d302727c9b54c } ],
  insertedCount: 1,
  insertedIds: { '0': 5aeb495e458d302727c9b54c } }
kondo: first
kondo: second
kondo: second

4.3.1 p105 あたり
ensureIndex ではなく、createIndex に変更しました。なかなか気づかなかったところは、データベースへの接続が非同期だという点です。client.close() を変なところに書いていると接続が切られてしまいます。

var mongo = require('mongodb');
var mongoClient = mongo.MongoClient;

mongoClient.connect('mongodb://localhost:27017', function (err, client){
	//console.log(client);
	var quotes = client.db("quotes");
	var collection = quotes.collection('quotes');

	collection.createIndex({'author':1}, function(err, result) {
		if(err) { throw err; }
		collection.distinct('author', function(err, result) {
			if(err) { throw err; client.close();}
			console.log(result.join('\n'));
			client.close();
		});
	});
});

4.3.2 p107 あたり
ここでは、先と同じ変更はするものの、新しい変更点はない。後半はそのまま動く。mongo.ObjectID や {safe:true} もそのままです。

var mongo = require('mongodb');
var params = { id: process.argv[2], voter: process.argv[3] };
var mongoClient = mongo.MongoClient;

mongoClient.connect('mongodb://localhost:27017', function (err, client){
	var quotes = client.db("quotes");
	var collection = quotes.collection('quotes');

	if(params.id) {
		collection.update({_id: new mongo.ObjectID(params.id)},
			{$inc: {votes: 1}},
			{safe:true}, function(err){
				if(err) { throw err; }
				collection.find().sort({votes: -1}).limit(10).each(function (err, doc) {
					if(err) { throw err; }
					if(doc) {
						var votes = (doc.votes) || 0;
						console.log(doc.author, doc.quote, votes);
						return;
					}
					client.close();
				});
		});
		return;
	}

	collection.find().each(function(err, doc){
		if(err) { throw err; }
		if(doc) { console.log(doc._id, doc.quote); return; }
		client.close();
	});
});

4.4 以降の4章
mongoskin を動かせない。情報もあまり見あたらないので、読まずに、飛ばします。その他のデータベース関連のところも飛ばします。

5.1 p135 あたり
websocket をバージョン を指定してインストールしました。エラーが出てはいます。

friend@xpython:~/scripts/5/5.1$ npm install websocket@1.0.7

> websocket@1.0.7 install /home/friend/scripts/5/5.1/node_modules/websocket
> node install.js

[websocket v1.0.7] Attempting to compile native extensions.
[websocket v1.0.7]
    Native code compile failed!!
    On Windows, native extensions require Visual Studio and Python.
    On Unix, native extensions require Python, make and a C++ compiler.
    Start npm with --websocket:verbose to show compilation output (if any).
5.1@1.0.0 /home/friend/scripts/5/5.1
└── websocket@1.0.7 

npm WARN 5.1@1.0.0 No description
npm WARN 5.1@1.0.0 No repository field.

サーバーを起動すると、localhost からのみですが動きました。アドレスを 192.168.100.18 などと記入した場合にはアクセスが許可されていません。

friend@xpython:~/scripts/5/5.1$ node server.js 
Warning: Native modules not compiled.  XOR performance will be degraded.
Warning: Native modules not compiled.  UTF-8 validation disabled.
http://192.168.100.18:8080からのアクセスは許可されていません
http://192.168.100.18:8080からのアクセスは許可されていません
"kondo" を http://localhost:8080 から受信
"kondo2" を http://localhost:8080 から受信
"Hello" を http://localhost:8080 から受信

下図は、クライアントの方です。

5.1.1 p141あたり
ここは先と同様に websocket のバージョンを 1.0.7 でインストールしただけです。サーバー側を起動して、クライアントから接続すると下記のようなメッセージが表示されます。

friend@xpython:~/scripts/5/5.1.1$ node server.js 
Warning: Native modules not compiled.  XOR performance will be degraded.
Warning: Native modules not compiled.  UTF-8 validation disabled.
"Hello" を http://localhost:8080 から受信
接続解除:1006 - Connection dropped by remote peer.

こちらはクライアント側の表示です。

friend@xpython:~/scripts/5/5.1.1$ node client.js 
Warning: Native modules not compiled.  XOR performance will be degraded.
Warning: Native modules not compiled.  UTF-8 validation disabled.
送信:Hello
受信:WebSocketサーバからこんにちは!

クライアントは終了はしません。

5.2 p142 あたり
socket.io のバージョンを 2.1.0 としました。下記はインストール時の画面です。

friend@xpython:~/scripts/5/5.2$ npm install socket.io
5.2@1.0.0 /home/friend/scripts/5/5.2
└─┬ socket.io@2.1.0 
  ├─┬ debug@3.1.0 
  │ └── ms@2.0.0 
  ├─┬ engine.io@3.2.0 
  │ ├─┬ accepts@1.3.5 
  │ │ ├─┬ mime-types@2.1.18 
  │ │ │ └── mime-db@1.33.0 
  │ │ └── negotiator@0.6.1 
  │ ├── base64id@1.0.0 
  │ ├── cookie@0.3.1 
  │ ├─┬ engine.io-parser@2.1.2 
  │ │ ├── after@0.8.2 
  │ │ ├── arraybuffer.slice@0.0.7 
  │ │ └── blob@0.0.4 
  │ └─┬ ws@3.3.3 
  │   ├── async-limiter@1.0.0 
  │   ├── safe-buffer@5.1.2 
  │   └── ultron@1.1.1 
  ├─┬ has-binary2@1.0.2 
  │ └── isarray@2.0.1 
  ├── socket.io-adapter@1.1.1 
  ├─┬ socket.io-client@2.1.0 
  │ ├── backo2@1.0.2 
  │ ├── base64-arraybuffer@0.1.5 
  │ ├── component-bind@1.0.0 
  │ ├── component-emitter@1.2.1 
  │ ├─┬ engine.io-client@3.2.1 
  │ │ ├── component-inherit@0.0.3 
  │ │ ├── xmlhttprequest-ssl@1.5.5 
  │ │ └── yeast@0.1.2 
  │ ├── has-cors@1.1.0 
  │ ├── indexof@0.0.1 
  │ ├── object-component@0.0.3 
  │ ├─┬ parseqs@0.0.5 
  │ │ └─┬ better-assert@1.0.2 
  │ │   └── callsite@1.0.0 
  │ ├── parseuri@0.0.5 
  │ └── to-array@0.1.4 
  └── socket.io-parser@3.2.0 

npm WARN 5.2@1.0.0 No description
npm WARN 5.2@1.0.0 No repository field.

そうすると、特に何もせずに動きました。

5.3.1 p151あたり
now のインストールをしました。

friend@xpython:~/scripts/5/5.3.1$ npm install now

> now@11.1.7 postinstall /home/friend/scripts/5/5.3.1/node_modules/now
> node download/install.js

> For the source code, check out: https://github.com/zeit/now-cli

> Downloading Now CLI 11.1.7 [====================] 100%

5.3.1@1.0.0 /home/friend/scripts/5/5.3.1
└── now@11.1.7 

npm WARN 5.3.1@1.0.0 No description
npm WARN 5.3.1@1.0.0 No repository field.

実行してもサーバーが起動しない。インストールが上手くいっていないのか?

friend@xpython:~/scripts/5/5.3.1$ node server.js 
module.js:471
    throw err;
    ^

Error: Cannot find module 'now'
    at Function.Module._resolveFilename (module.js:469:15)
    at Function.Module._load (module.js:417:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object. (/home/friend/scripts/5/5.3.1/server.js:8:31)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)

ここに少し情報あり。現在の now は別物だとある。ここで止める。

5.4 p153 あたり
widget-server.js が起動しない。

friend@xpython:~/scripts/5/5.4$ node widget_server.js 
/home/friend/scripts/5/5.4/widget_server.js:8
io.configure(function () {
   ^

TypeError: io.configure is not a function
    at Object. (/home/friend/scripts/5/5.4/widget_server.js:8:4)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3

とりあえず動いてくれないと内容がさっぱり理解できない。

あたり