StaxのBlazeDSでCometによるチャットを作る

f:id:voidy21:20090217033142p:image
前回のStaxでBlazeDSを始めてみるに続いて
今回はStaxでBlazeDSによるCometチャットを作ってみたいと思います。


Cometとはサーバ・プッシュ型の通信技術で、Cometを使うとサーバからの命令・メッセージをほぼリアルタイムにクライアント側のブラウザに反映させることが可能になります。
実際にはクライアントのコネクションを張り続けるために、Long Pollingなどによって処理しています。
BlazeDSではLong PollによるCometが可能なので、これを使ってみたいと思います。

参考URL:http://www.stbbs.net/blog/2008/05/blazeds-flexpubsub.html

準備

(stax-sdk)/webapp/WEB-INF/flex/services-config.xmlを見る
デフォルトのままだと動かしたときに負荷が大きすぎるのでタグ内を以下のような感じに修正する

<channel-definition id="my-polling-amf"  class="mx.messaging.channels.AMFChannel">
    <endpoint 
        url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" 
        class="flex.messaging.endpoints.AMFEndpoint"/>
    <properties>
         <polling-enabled>true</polling-enabled>
         <polling-interval-millis>0</polling-interval-millis>
         <wait-interval-millis>-1</wait-interval-millis>
         <max-waiting-poll-requests>300</max-waiting-poll-requests>
    </properties>
</channel-definition>


(stax-sdk)/webapp/WEB-INF/flex/messaging-config.xmlに追加

<service id="message-service" 
    class="flex.messaging.services.MessageService">
(中略)
<destination id="hoge"/> 
</service>

ここではhogeというidのdestinationを用意しておきました。
基本的にこれだけで準備はいいですが、新しくswfファイルとかを作りたいときはコンパイル時のターゲットなどを書く設定ファイル(stax-sdk)/stax-build.xmlを適宜変更するといいと思います。

Flexソース

(stax-sdk)/flex-src/main.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
    <![CDATA[
    import mx.controls.Alert;
    import mx.messaging.messages.AsyncMessage;
    ]]>
  </mx:Script>
  <mx:ChannelSet id="channelSet">
    <!--
    requestTimeout=-1 HTTPリクエストをタイムアウトさせずメッセージを待ち続ける
    pollingInterval=0 HTTPリクエストが終了したら即座に次のリクエストを発生させる
    -->
    <mx:AMFChannel
      uri="./messagebroker/amfpolling"
      requestTimeout="-1" pollingInterval="0"/> 
  </mx:ChannelSet>
  <mx:Consumer id="consumer" 
    channelSet="{channelSet}" destination="hoge">
    <mx:message>
      <![CDATA[
        // メッセージが飛んできた時の処理
       var pushData:Object =  (event as MessageEvent).message.body as Object;
        var name:String = pushData.name.toString() ;
        if(name==""){
                name = "名無し";
        }
        var body:String = pushData.body.toString() ;
        var date:String = pushData.date.toString();
        message.text +=  (name +"さんの発言("+date+"):"+body+ "\n");
      ]]>
    </mx:message>
 </mx:Consumer>
 <mx:Producer id="producer" channelSet="{channelSet}" 
    destination="hoge"/>
  <mx:creationComplete>
    <![CDATA[
      // subscribeをしないとメッセージは飛んでこない
      consumer.subscribe(null);
    ]]>
  </mx:creationComplete>
  <mx:HBox label="Comment">
	 <mx:VBox>
		<mx:VBox  width="100%" paddingLeft="10" paddingRight="10" paddingTop="10" paddingBottom="10">
			<mx:HBox  width="100%">
			<mx:Label color="blue" text="名前"/>
			<mx:TextInput id="username"  width="100"/>
			</mx:HBox>
			<mx:TextArea width="100%"  id="maintext">
	            	<mx:text></mx:text>
	        	</mx:TextArea>
                        <mx:Button label="Submit">
                             <mx:click>
                             <![CDATA[
                                function xSetDights(n:int,d:int=2):String {
                                  var temp_str:String = String(n+100);
                                  var n_str:String = temp_str.substring(temp_str.length-d);
                                  return n_str;
                                }
                               var msg:AsyncMessage = new AsyncMessage;
                               var pushObj : Object = new Object();
                                var my_date:Date = new Date();
                                var nYear:Number = my_date.fullYear;
                                var nMonth:Number = my_date.month+1;
                                var nDate:Number = my_date.date;
                                var nHours:Number = my_date.hours;
                                var nMinutes:Number = my_date.minutes;
                                var nSeconds:Number = my_date.seconds;
                                var nMilliseconds:Number = my_date.milliseconds;
                                var sDate:String=nYear+"/"+xSetDights(nMonth)+"/"+xSetDights(nDate)
                                        +" "+xSetDights(nHours)+":"+xSetDights(nMinutes)+":"
                                        +xSetDights(nSeconds)+"."+xSetDights(nMilliseconds,3);
                               pushObj["body"] = maintext.text;
                               pushObj["name"] = username.text;
                               pushObj["date"] = sDate;
                               msg.body = pushObj;

                               producer.send(msg);
                            ]]>
                         </mx:click>
                   </mx:Button>
                </mx:VBox>
        </mx:VBox>
</mx:HBox>
    <mx:HBox width="100%">
    <mx:TextArea width="90%" height="120" id="message">
    <mx:text></mx:text>
  </mx:TextArea>
  </mx:HBox>
</mx:Application>

あとはコンソールにstax runと打ち込むだけです!!

ポイント

  • 今回はFlexのみで作った
  • でサーバサイド送信
  • でクライアント処理
  • AsyncMessage型のbodyプロパティにはObject型が入る→どんなデータもプッシュ送信


完成サンプルは http://chattest.voidy21.staxapps.net/ です
2つ以上開いてみるとCometの効果がわかると思います!!(でも少し遅いかも)