ですが、時には管理画面や、バッチの処理によってユーザーに何か通知をしたいことがあるかもしれません。
今度はredisを利用して、システム管理者とユーザーの間でリアルタイム通信を行なってみます。
以前紹介したFuelPHPもまた、キャッシュストアや、クライアントインターフェースとしてRedisをサポートしています。
そこで、FuelPHPで管理画面をつくり、ボタンを押すとチャット中のユーザーに管理者からのメッセージを表示させたいと思います。
チャットプログラムや構成は前々回の構成のまま、node1, node2という2つのサーバーがredisサーバーにつながってセッション共有されている状態とします。
今回は、以下のように、さらにadminサーバーを追加し、管理画面を置きます。
上図のように、fuelphpからredisにpublishしたものを同じadminサーバー上のsocket.ioでsubscribeし、チャットサーバーへブロードキャストするイメージです。
チャットサーバーが直接subscribeすることも可能ですが、そうすると、チャットサーバーの数だけsubscribe→emitが発生して、メッセージが重複してしまいます。subscribe→emit役は1つである必要があるので、adminサーバーに兼任させます。
なので、既存のチャットサーバーには手を加える必要がなく、adminサーバーだけ用意して実装すればいいわけです。
それでは実際に用意してみます。
まず必要なユーザーやライブラリを用意します。
FuelPHPの最新版(v1.4)では、タイムゾーンの指定が必至になったのでphp.iniで設定します。
次にアプリユーザーのホームディレクトリをApacheからアクセス可能にします。
アプリを作成します。
publishボタンを配置する画面(index)とpublishボタンの押下(publish)の2つのアクションを用意します。
次に、DocumentRootをFuelPHPのpublicディレクトリに向けます。
そして、Apacheの設定をシンボリックリンクをたどり、.htaccessを許可するように変更し、起動します。
次にFuelPHPのconfig/db.phpおよび、viewとcontrollerを以下のように実装します。
fuel/app/config/db.php
redisの接続先を指定します。チャットサーバーが参照しているのと同じサーバーに接続させるようにします。
fuel/app/views/greeting/index.php
Publishボタンを配置します。
fuel/app/classes/controller/greeting.php
publishアクション内で、Redisクラスをインスタンス化しています。
ここでの引数defaultは、db.phpで設定したラベルを指定します。
そして、publishメソッドを呼び出すことにより、redisサーバーに「greeting」というチャンネルでpublishを行います。
ここまでで、管理画面自体は完成です。
以下のようにPublishボタンがあるだけのシンプルな画面になっています。
つづいて、同じadminサーバーに、node.jsを入れて動かします。
モジュールはforever, socket.io, redisを入れます。
socket.ioにもredisが含まれているのですが、requireのしやすさやバージョンが新しさなどのため、別途いれておきます。
これでnodeのインストールができました。
それでは、subscribe→emit用にnodeのスクリプトを実装します。
ポイントは、チャット用のスクリプトと同じようにredisサーバーをRedisStoreとしてstore登録することと、
それとは別にsubscribe用のredisクライアントを作り、「greeting」チャンネルをsubscribeし、受信したメッセージをチャット参加者全員にemitするようにするところです。
これを起動します。
$ forever start admin.js
それでは、実際に動かしてみましょう。
まず、前回と同様、node1とnode2のチャットウィンドウを開いて、適当にチャットしてみます。
それでは、ここで先程の管理画面でPublishボタンを押してみます。
そして、チャット画面をみてみます。
おお!メッセージが表示されました。
これで管理画面からのコントロールも可能になりました。
以上です。
チャットプログラムや構成は前々回の構成のまま、node1, node2という2つのサーバーがredisサーバーにつながってセッション共有されている状態とします。
今回は、以下のように、さらにadminサーバーを追加し、管理画面を置きます。
+----------+ +---------+ | admin | | redis | |----------| pub |---------| | fuelphp +-------> | | | sub | redis | | admin.js <-------+ | +-----+----+ +---------+ | +-----------------+ | emit | +-----v----+ +----v----+ | node1 | | node2 | |----------| |---------| | chat.js | | chat.js | +----------+ +---------+
上図のように、fuelphpからredisにpublishしたものを同じadminサーバー上のsocket.ioでsubscribeし、チャットサーバーへブロードキャストするイメージです。
チャットサーバーが直接subscribeすることも可能ですが、そうすると、チャットサーバーの数だけsubscribe→emitが発生して、メッセージが重複してしまいます。subscribe→emit役は1つである必要があるので、adminサーバーに兼任させます。
なので、既存のチャットサーバーには手を加える必要がなく、adminサーバーだけ用意して実装すればいいわけです。
それでは実際に用意してみます。
まず必要なユーザーやライブラリを用意します。
# useradd appadmin # passwd appadmin # yum install -y vim git wget php gcc gcc-c++ make # curl get.fuelphp.com/oil | sh
FuelPHPの最新版(v1.4)では、タイムゾーンの指定が必至になったのでphp.iniで設定します。
# vim /etc/php.ini --- date.timezone = Asia/Tokyo --
次にアプリユーザーのホームディレクトリをApacheからアクセス可能にします。
# chmod 755 /home/appadmin
アプリを作成します。
publishボタンを配置する画面(index)とpublishボタンの押下(publish)の2つのアクションを用意します。
# su - appadmin $ oil create app $ cd app $ oil g controller greeting index publish
次に、DocumentRootをFuelPHPのpublicディレクトリに向けます。
$ exit # cd /var/www/ # mv html html.org # ln -s /home/appadmin/app/public html
そして、Apacheの設定をシンボリックリンクをたどり、.htaccessを許可するように変更し、起動します。
# vim /etc/httpd/conf/httpd.conf --- <Directory "/var/www/html"> ~略~ Options FollowSymLinks ~略~ AllowOverride All ~略~ </Directory> --- # /etc/init.d/httpd start
次にFuelPHPのconfig/db.phpおよび、viewとcontrollerを以下のように実装します。
fuel/app/config/db.php
redisの接続先を指定します。チャットサーバーが参照しているのと同じサーバーに接続させるようにします。
$ vim fuel/app/config/db.php <?php /** * Use this file to override global defaults. * * See the individual environment DB configs for specific config information. */ return array( 'redis' => array( 'default' => array( 'hostname' => '10.0.0.200', 'port' => 6379 ) ), );
fuel/app/views/greeting/index.php
Publishボタンを配置します。
$ vim fuel/app/views/greeting/index.php
---
<p>Index</p>
<?php echo Form::open('greeting/publish'); ?>
<?php echo Form::submit('publish', 'publish'); ?>
<?php echo Form::close(); ?>
---
fuel/app/classes/controller/greeting.php
publishアクション内で、Redisクラスをインスタンス化しています。
ここでの引数defaultは、db.phpで設定したラベルを指定します。
そして、publishメソッドを呼び出すことにより、redisサーバーに「greeting」というチャンネルでpublishを行います。
$ vim fuel/app/classes/controller/greeting.php
---
<?php
class Controller_Greeting extends Controller_Template
{
    public function action_index()
    {
        $this->template->title = 'Greeting » Index';
        $this->template->content = View::forge('greeting/index');
    
    public function action_publish()
    {
        $redis = Redis::instance('default');
        $redis->publish('greeting', 'おはよう諸君!!');
        $this->template->title = 'Greeting » Publish';
        $this->template->content = View::forge('greeting/publish');
    }
}
---
ここまでで、管理画面自体は完成です。
以下のようにPublishボタンがあるだけのシンプルな画面になっています。
つづいて、同じadminサーバーに、node.jsを入れて動かします。
モジュールはforever, socket.io, redisを入れます。
socket.ioにもredisが含まれているのですが、requireのしやすさやバージョンが新しさなどのため、別途いれておきます。
# cd /usr/local/src # wget http://nodejs.org/dist/v0.8.14/node-v0.8.14.tar.gz # tar xzvf node-v0.8.14.tar.gz # cd node-v0.8.14 # ./configure # make # make install # curl https://npmjs.org/install.sh | sh # npm install -g socket.io # npm install -g forever # npm install -g redis
これでnodeのインストールができました。
それでは、subscribe→emit用にnodeのスクリプトを実装します。
# su - appadmin
$ mkdir -p /home/appadmin/admin/node
$ cd /home/appadmin/admin/node
$ vim admin.js
---
var server = require('http').createServer(function(req, res){
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('server connected');
});
server.listen(3001);
var io = require('socket.io').listen(server);
var RedisStore = require('socket.io/lib/stores/redis');
var opts = {host:'10.0.0.200', port:6379};
io.set('store', new RedisStore({redisPub:opts, redisSub:opts, redisClient:opts}));
var redis = require('redis');
var sub = redis.createClient(opts.port, opts.host);
sub.subscribe('greeting');
sub.on("message", function(channel, message){
  io.sockets.emit('msg', {msg:message});
});
---
ポイントは、チャット用のスクリプトと同じようにredisサーバーをRedisStoreとしてstore登録することと、
それとは別にsubscribe用のredisクライアントを作り、「greeting」チャンネルをsubscribeし、受信したメッセージをチャット参加者全員にemitするようにするところです。
これを起動します。
$ forever start admin.js
それでは、実際に動かしてみましょう。
まず、前回と同様、node1とnode2のチャットウィンドウを開いて、適当にチャットしてみます。
それでは、ここで先程の管理画面でPublishボタンを押してみます。
そして、チャット画面をみてみます。
おお!メッセージが表示されました。
これで管理画面からのコントロールも可能になりました。
以上です。



