其の五:hubotの文字化けを直す
前回、hubotが無事インストールできたので、文字化けを対策する。
hubotで扱う文字コードはUTF-8が前提となっており、会社で使っているISO-2022-JPのチャットサーバーだと、文字化けを起こしてしまう。
以前perlのnkfモジュールを用いて対策を行ったことがあったが、coffeeスクリプトで対策できることが分かったので、そちらで対策する。
まずは、hubotをインストールしたディレクトリに移動して、必要なモジュール(jschardet、iconv)を追加インストールする。
$ cd ~/hubot
$ npm install jschardet
$ npm install iconv
次に、irc.coffeeに修正を加える。
$ cd ~/hubot/node_modules/hubot-irc/src
$ cp irc.coffee irc.coffee.org
$ vi irc.coffee
修正内容(diffイメージ)は以下で、最初にrequireで追加したモジュールをロード。
日本語のチャンネル名が指定された場合に備えて、チャンネル名をUTF8からISO-2022-JPに変更する処理を追加。
sendメソッドとnoticeメソッドに文字コードをUTF-8からISO-2022-JPに変更する処理を追加。messageやchannelを受け取るbotListener(message,notice等)に受け取った文字をUTF-8に変更する処理を追加。
ちなみに、iconv生成時のパラメータで指定している『TRANSLIT//IGNORE』はコード変換失敗時にエラーを無視するためのおまじないみたい。
# Irc library
Irc = require 'irc'
+# for ISO-2022-JP
+Jschardet = require 'jschardet'
+Iconv = (require 'iconv').Iconv
+
class IrcBot extends Adapter
send: (envelope, strings...) ->
# Use @notice if SEND_NOTICE_MODE is set
@@ -15,6 +19,8 @@
return console.log "ERROR: Not sure who to send to. envelope=", envelope
for str in strings
+ iconv = new Iconv('UTF-8','ISO-2022-JP//TRANSLIT//IGNORE')
+ str = iconv.convert(str).toString()
@bot.say target, str
topic: (envelope, strings...) ->
@@ -52,6 +58,8 @@
if not str?
continue
+ iconv = new Iconv('UTF-8','ISO-2022-JP//TRANSLIT//IGNORE')
+ str = iconv.convert(str).toString()
@bot.notice target, str
reply: (envelope, strings...) ->
@@ -131,11 +139,15 @@
do @checkCanStart
+ iconv = new Iconv('UTF-8','ISO-2022-JP//TRANSLIT//IGNORE')
+ roomsValue = iconv.convert(process.env.HUBOT_IRC_ROOMS).toString()
+
options =
nick: process.env.HUBOT_IRC_NICK or @robot.name
realName: process.env.HUBOT_IRC_REALNAME
port: process.env.HUBOT_IRC_PORT
- rooms: process.env.HUBOT_IRC_ROOMS.split(",")
+# rooms: process.env.HUBOT_IRC_ROOMS.split(",")
+ rooms: roomsValue.split(",")
ignoreUsers: process.env.HUBOT_IRC_IGNORE_USERS?.split(",") or []
server: process.env.HUBOT_IRC_SERVER
password: process.env.HUBOT_IRC_PASSWORD
@@ -189,15 +201,27 @@
if options.connectCommand?
bot.addListener 'registered', (message) ->
+ detectResult = Jschardet.detect(message)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ message = iconv.convert(message).toString()
+
# The 'registered' event is fired when you are connected to the server
strings = options.connectCommand.split " "
self.command strings.shift(), strings...
bot.addListener 'names', (channel, nicks) ->
+ detectResult = Jschardet.detect(channel)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ channel = iconv.convert(channel).toString()
+
for nick of nicks
self.createUser channel, nick
bot.addListener 'notice', (from, to, message) ->
+ detectResult = Jschardet.detect(message)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ message = iconv.convert(message).toString()
+
if from in options.ignoreUsers
console.log('Ignoring user: %s', from)
# we'll ignore this message if it's from someone we want to ignore
@@ -209,6 +233,10 @@
self.receive new TextMessage(user, message)
bot.addListener 'message', (from, to, message) ->
+ detectResult = Jschardet.detect(message)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ message = iconv.convert(message).toString()
+
if options.nick.toLowerCase() == to.toLowerCase()
# this is a private message, let the 'pm' listener handle it
return
@@ -231,6 +259,10 @@
self.receive new TextMessage(user, message)
bot.addListener 'action', (from, to, message) ->
+ detectResult = Jschardet.detect(message)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ message = iconv.convert(message).toString()
+
console.log " * From #{from} to #{to}: #{message}"
if from in options.ignoreUsers
@@ -247,9 +279,17 @@
self.receive new TextMessage(user, message)
bot.addListener 'error', (message) ->
+ detectResult = Jschardet.detect(message)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ message = iconv.convert(message).toString()
+
console.error('ERROR: %s: %s', message.command, message.args.join(' '))
bot.addListener 'pm', (nick, message) ->
+ detectResult = Jschardet.detect(message)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ message = iconv.convert(message).toString()
+
console.log('Got private message from %s: %s', nick, message)
if process.env.HUBOT_IRC_PRIVATE
@@ -267,21 +307,37 @@
self.receive new TextMessage({reply_to: nick, name: nick}, message)
bot.addListener 'join', (channel, who) ->
+ detectResult = Jschardet.detect(channel)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ channel = iconv.convert(channel).toString()
+
console.log('%s has joined %s', who, channel)
user = self.createUser channel, who
user.room = channel
self.receive new EnterMessage(user)
bot.addListener 'part', (channel, who, reason) ->
+ detectResult = Jschardet.detect(channel)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ channel = iconv.convert(channel).toString()
+
console.log('%s has left %s: %s', who, channel, reason)
user = self.createUser '', who
user.room = channel
self.receive new LeaveMessage(user)
bot.addListener 'kick', (channel, who, _by, reason) ->
+ detectResult = Jschardet.detect(channel)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ channel = iconv.convert(channel).toString()
+
console.log('%s was kicked from %s by %s: %s', who, channel, _by, reason)
bot.addListener 'invite', (channel, from) ->
+ detectResult = Jschardet.detect(channel)
+ iconv = new Iconv(detectResult.encoding,'UTF-8//TRANSLIT//IGNORE')
+ channel = iconv.convert(channel).toString()
+
console.log('%s invited you to join %s', from, channel)
if from in options.ignoreUsers
本来なら、環境変数もしくはコマンドパラメータで変換する文字コードを指定すべきだが、今回はそこまでやってない。
上記修正が正しく動作するか確認するために、hubot-scriptsのhttp-post-say.coffeeを使ったため、それの設定方法も残しておく。
まず、hubotインストールディレクトリに移動して、hubot-scripts.jsonを編集。
$ cd ~/hubot
$ vi hubot-scripts.json
hubot-scripts.jsonの内容は以下。他に追加したいスクリプトがあればカンマ(,)区切りで追加すればよい。
["http-post-say.coffee"]
hubotの待ち受けポートは、デフォルト8080になっている。変更する場合には、以下のようにhubot起動スクリプトに環境変数PORTの設定処理を追加し、起動すればよい。
$ vi runbot.sh
#!/bin/bash
# hubot http port setting
export PORT=9999
# runhubot
export HUBOT_IRC_NICK="hubot"
export HUBOT_IRC_ROOMS="#test01,#test02"
export HUBOT_IRC_SERVER="localhost"
#export HUBOT_IRC_PASSWORD="hoge"
bin/hubot -a irc
$ .runbot.sh
http-post-say.coffeeを使って、http経由でhubotに発言させるにはcurlコマンド等で以下のようにすればよい。
$ curl -X POST http://localhost:9999/hubot/say -d message=文字化けた? -d room='#test01'
ISO-2022-JPのチャットサーバって、世の中一般では、レアなんですかね。。。うちの会社だけなのかなぁ。。。。
あと、おまけで、hubotの発言をnoticeにする方法がわかった。すごく簡単で、起動時に環境変数HUBOT_IRC_SEND_NOTICE_MODEにtrueを設定するだけだった。イメージは以下。
#!/bin/bash
# hubot http port setting
export PORT=9999
# runhubot
export HUBOT_IRC_NICK="hubot"
export HUBOT_IRC_ROOMS="#test01,#test02"
export HUBOT_IRC_SERVER="localhost"
#export HUBOT_IRC_PASSWORD="hoge"
export HUBOT_IRC_SEND_NOTICE_MODE="true"
bin/hubot -a irc