peerjs-server経由でチャット

概要

チャットとかのログを残すためにサーバ経由でチャットを送るようにしたかった。
それのためにシグナリングサーバに無理やりくっつけた。

実装

クライアント

  • peer.chat()でチャットを送り、type:CHATのデータをチャットデータとして受信・処理する。
  • ユーザ名とかはいったん毎回送ってる

added chat event · kambayashia/peerjs@f1663c1 · GitHub

サーバ

  • _handleTransmission()のハンドリングにCHATを加える
  • ログ残すのはまた別途
  • ルーム内全員に転送する
  • あとはちょっとバグ修正

added chat event · kambayashia/peerjs-server@73c9889 · GitHub

使い方

# 受信側
peer.on('chat', function(src, payload) {
      /**
       * payload = {
       *     name: "namae",
       *     message: "hogehoge"
       * };
       */

       // DOMにくっつける処理
});

# 送信側
peer.chat(name, message);

まとめ

peerjs-serverいろいろかえてくのやっぱり辛いなと思った。 そして毎回xhr対応忘れてる。

peerjsでping-pong

概要

herokuでpeerjsサーバ動かしたら60秒くらいでWebSocketが切断する問題が起きた。
ドキュメント見たら、30秒?で切れるようなので、しかたなくping−pongを実装した。

WebSockets on Heroku | Heroku Dev Center

実装

クライアント

  • 受信したPINGに返答を返す

added ping-pong · kambayashia/peerjs@d2b0a26 · GitHub

サーバ

peerjsにルーム機能と切断検知機能をつける

概要

peerjsを使ってWebRTC実装したときに、FireFoxだとcloseイベントが通知されなかったので1meetingのjsを参考に、ルーム管理と切断検知を作ってみた。

コード

サーバ

github.com

クライアント

github.com

ルーム情報送信

  • 最初の接続時に接続ルーム名を送る
  • ページ遷移なしでルームをうつることは考えない

クライアント

  • アクセスパラメータにルーム名を入れる

added room name · kambayashia/peerjs@0717e2c · GitHub

サーバ

  • ルーム名を受け取ってルームごとのリストに分ける

added room list · kambayashia/peerjs-server@0187de5 · GitHub

ルームメンバー取得

  • ルームメンバー一覧を返すアクションを作る

クライアント

  • ルーム取得時に再度ルーム名送ってるのが気になるけどいったんしょうがない。

added getter of room-member · kambayashia/peerjs@ded674a · GitHub

サーバ

  • id一覧をarrayで返す

added handler · kambayashia/peerjs-server@c800802 · GitHub

使い方

  • OPENイベントのpayloadに乗っけて返そうとしたけど、自身のMediaStreamが必要だったのでgetUserMedia()のコールバック内で呼ぶようにした。
var peer; //Peerオブジェクト
navigator.getUserMedia({audio: true, video: true}, function(stream){
    peer.listRoomMemberPeers(function (response) {
        for(var i in response) {
            var id = response[i];
            if (id != peer.id) {     // 自分自身のも含んでるので弾く
               peer.call(id, stream);
            }
        }
    });
});

切断通知

  • 切断した際に相手にLEAVEイベントが行っていなかったので、飛ばすようにした。

クライアント

  • 変更なし

サーバ

  • removePeer()が呼ばれたら内部で同一ルームのメンバーにLEAVEを投げる

send leave event to room members · kambayashia/peerjs-server@dfb8a63 · GitHub

まとめ

元の実装みると次にpeerjs−server経由で通信しようとしたときに切断されていたらLEAVEイベント投げるっぽいけど、定期的に投げられるものじゃないっぽいので自分で投げるようにした。 FireFoxでは相手の切断イベントがこない問題はいったんこれで解決した。 他の方法がどんなのがあるかわからないけど、1meetingも独自イベント実装してたしまあいいかなと。

あと、動画部分はさておき、テキストチャットその他の操作をルームごとのアーカイブとして残したいので、WebRTCのデータチャンネルを使わずに、サーバクライアント方式でチャットやり取りする機能をpeerjsにつける魔改造をする予定。 1つのページで複数WebSocket作って、別サーバに接続に行くのがスマートなのかよくわからない。

vagrantでdebian wheezyの環境を作る

最近仕事でもvagrantを使うのでいろいろ覚えつつ、個人用環境を作ってみた。

vagrantとは

vagrantの使い方やってるページはいろいろあるのでそのへんで

詰まったところ

chefがインストールできない

とりあえず http://www.vagrantbox.es/ からwheezyのvanillaって書いてあるやつを持ってきて入れた。
chefが入ってないので vagrant-omunibusを使う。
ssl的なエラーが出てインストールできない。

# Vagrantfile

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.omnibus.chef_version = :latest
  :
  :
  :
# ログ
Please detail your operating system type, version and any other relevant details
Metadata URL: https://www.opscode.com/chef/metadata?v=11.8.2&prerelease=false&p=debian&pv=6&m=x86_64
\nDEBUG OUTPUT FOLLOWS:\n\nSTDERR from wget:\n\n--2013-12-22 09:14:57--  https://www.opscode.com/chef/metadata?v=11.8.2&prerelease=false&p=debian&pv=6&m=x86_64
Resolving www.opscode.com (www.opscode.com)... 184.106.28.90
Connecting to www.opscode.com (www.opscode.com)|184.106.28.90|:443... connected.
ERROR: The certificate of `www.opscode.com' is not trusted.

opscodeからもってきたレシピがインストールできない

http://www.vagrantbox.es/ からchefが入ってるwheezy(Debian Wheezy 7.1 amd64 (french) with Chef 11.4.4 and VirtualBox 4.1.18)を持ってきて入れた。
適当にmysql::serverとか入れてみるけどapparmor-utilsがどうとかでインストールできない。
ぶっちゃけこのへんの関係が知りたいわけじゃないから原因は調べてない

================================================================================
Error executing action `install` on resource 'package[apparmor-utils]'
================================================================================


Chef::Exceptions::Exec
----------------------
apt-get -q -y install apparmor-utils=2.7.103-4 returned 100, expected 0


Resource Declaration:
---------------------
# In /tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/recipes/_server_debian.rb

 28:   package name do
 29:     action :install
 30:   end
 31: end

パッケージのマイナーバージョンが違ってインストールできない

recipe[mysql::server]と書いて実行すると下記のように404になる。

fter this operation, 98.5 MB of additional disk space will be used.
Get:1 http://ftp.us.debian.org/debian/ wheezy/main libaio1 amd64 0.3.109-3 [9,150 B]
Get:2 http://ftp.us.debian.org/debian/ wheezy/main libnet-daemon-perl all 0.48-1 [46.2 kB]
Err http://security.debian.org/ wheezy/updates/main mysql-common all 5.5.31+dfsg-0+wheezy1
  404  Not Found [IP: 200.17.202.197 80]
Get:3 http://ftp.us.debian.org/debian/ wheezy/main libplrpc-perl all 0.2020-2 [36.0 kB]
Get:4 http://ftp.us.debian.org/debian/ wheezy/main libdbi-perl amd64 1.622-1 [898 kB]
Err http://security.debian.org/ wheezy/updates/main libmysqlclient18 amd64 5.5.31+dfsg-0+wheezy1
  404  Not Found [IP: 200.17.202.197 80]
Err http://security.debian.org/ wheezy/updates/main mysql-client-5.5 amd64 5.5.31+dfsg-0+wheezy1
  404  Not Found [IP: 200.17.202.197 80]
Err http://security.debian.org/ wheezy/updates/main mysql-server-core-5.5 amd64 5.5.31+dfsg-0+wheezy1
  404  Not Found [IP: 200.17.202.197 80]
Err http://security.debian.org/ wheezy/updates/main mysql-server-5.5 amd64 5.5.31+dfsg-0+wheezy1

実際にサイトに言ってみると5.5.33しかない。
f:id:kambayashi:20131224001003p:plain

mysqlがdebian7に対応してない

このへんの問題
https://github.com/opscode-cookbooks/mysql/pull/132
下記のようなエラー

Chef::Exceptions::FileNotFound
------------------------------
Cookbook 'mysql' (4.0.14) does not contain a file at any of these locations:
  templates/debian-7.0/init-mysql.conf.erb
  templates/debian/init-mysql.conf.erb
  templates/default/init-mysql.conf.erb

This cookbook _does_ contain: ['/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/default/debian.cnf.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/default/grants.sql.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/default/my.cnf.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/default/mysql-server.seed.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/default/port_mysql.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/default/usr.sbin.mysqld.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/ubuntu-10/init-mysql.conf.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/ubuntu-12/init-mysql.conf.erb','/tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/templates/windows/my.ini.erb']

Resource Declaration:
---------------------
# In /tmp/vagrant-chef-1/chef-solo-1/cookbooks/mysql/recipes/_server_debian.rb

 77: template '/etc/init/mysql.conf' do
 78:   source 'init-mysql.conf.erb'
 79: end

phpiisの部分でどうとかいわれる

下記近辺で定義がない感じのエラーが出る。
このへん
https://github.com/opscode-cookbooks/iis/blob/master/libraries/helper.rb#L29

Relevant File Content:
----------------------
/tmp/vagrant-chef-1/chef-solo-1/cookbooks/iis/libraries/helper.rb:

 23:    require 'chef/win32/version'
 24:  end
 25:
 26:  module Opscode::IIS
 27:    class Helper
 28:
 29:      def self.older_than_windows2008r2?
 30>>       win_version = Chef::ReservedNames::Win32::Version.new

解決方法

opscodeのクックブックの問題かboxファイルの問題かわからなくなるからvanillaに最小限の変更をいれたboxファイルを作ることにした。
まずvanillaをそのまま起動する。

$ vagrant box add debian-wheezy-vanilla https://dl.dropboxusercontent.com/s/xymcvez85i29lym/vagrant-debian-wheezy64.box
$ vagrant init debian-wheezy-vanilla
$ vagrant up

sshでログインしてssl関係のものをインストールする(最初のchefがインストール出来なかった問題用)

mac$ vagrant ssh

vagrant$ sudo apt-get install ca-certificates

ログアウトしてboxファイルを作る

mac$ vagrant package
[default] Attempting graceful shutdown of VM...
[default] Clearing any previously set forwarded ports...
[default] Creating temporary directory for export...
[default] Exporting VM...
[default] Compressing package to: /Users/kambayashia/projects/vagrant-files/test/package.box

作成したboxをvagrantに登録してそれを使うようにする。

Vagrantfileにaptを加えてrun_listにも加える。
これで最初にapt-get updateされる(マイナーバージョンが違って404になる問題用)

# Vagrantfile
     :
     :
    chef.run_list = [
      "recipe[apt::default]",
     :
     :

debian7対応がまだマージされてないので、Berksfileのmysqlをいったん独自リポジトリにする。
下記ブランチ、変更点はコミット履歴で
https://github.com/kambayashia/cookbooks-mysql/tree/debian7

cookbook 'mysql', github: "kambayashia/cookbooks-mysql", branch: "debian7"

phpiisはmetadata.rbにdependsが入ってるから起きてるけど、みんなどうやって解決してるのか知りたい。
https://github.com/opscode-cookbooks/php/blob/master/metadata.rb#L12
とりあえずこれも独自リポジトリにしちゃう

cookbook 'php', github: "kambayashia/cookbooks-php"

これでvagrant upすればとりあえずいけた。
すでにberkshelfのがダウンロードされてたらberks updateも必要かも。

リポジトリはこちら
https://github.com/kambayashia/vagrant-files

cakephp HttpResponseがクラス名かぶってる

概要

  • cakephp 2.2でhttpSocket使ってスクレイピングしようとしたけど、戻り値のHttpResponseにあるべきプロパティやメソッドがない

サンプルコード

    public function index(){
        // disable view
        $this->autoRender = false;

        App::uses('HttpSocket', 'Network/Http');
        $http = new HttpSocket();
        $url = "http://cakephp.jp/";
        $response = $http->get( $url );
        if( ! $response ){
            return false;
        }

        echo $response->body();
    }

画面表示

Fatal error: Call to undefined method HttpResponse::body() in /home/atsushi-kambayashi/www/app/Controller/HogeController.php on line 29

メソッド一覧確認

下記コードでメソッド一覧確認

    public function index(){
        // disable view
        $this->autoRender = false;

        App::uses('HttpSocket', 'Network/Http');
        $http = new HttpSocket();
        $url = "http://cakephp.jp/";
        $response = $http->get( $url );
        if( ! $response ){
            return false;
        }

        echo "<pre>";
        var_dump( get_class_methods( $response ) );
        echo "</pre>";

        echo $response->body();
    }

出力はこんな感じ

array(34) {
  [0]=>
  string(9) "setHeader"
  [1]=>
  string(9) "getHeader"
  [2]=>
  string(7) "setETag"
  [3]=>
  string(7) "getETag"
  [4]=>
  string(15) "setLastModified"
  [5]=>
  string(15) "getLastModified"
  [6]=>
  string(21) "setContentDisposition"
  [7]=>
  string(21) "getContentDisposition"
  [8]=>
  string(14) "setContentType"
  [9]=>
  string(14) "getContentType"
  [10]=>
  string(16) "guessContentType"
  [11]=>
  string(8) "setCache"
  [12]=>
  string(8) "getCache"
  [13]=>
  string(15) "setCacheControl"
  [14]=>
  string(15) "getCacheControl"
  [15]=>
  string(7) "setGzip"
  [16]=>
  string(7) "getGzip"
  [17]=>
  string(16) "setThrottleDelay"
  [18]=>
  string(16) "getThrottleDelay"
  [19]=>
  string(13) "setBufferSize"
  [20]=>
  string(13) "getBufferSize"
  [21]=>
  string(7) "setData"
  [22]=>
  string(7) "getData"
  [23]=>
  string(7) "setFile"
  [24]=>
  string(7) "getFile"
  [25]=>
  string(9) "setStream"
  [26]=>
  string(9) "getStream"
  [27]=>
  string(4) "send"
  [28]=>
  string(7) "capture"
  [29]=>
  string(8) "redirect"
  [30]=>
  string(6) "status"
  [31]=>
  string(17) "getRequestHeaders"
  [32]=>
  string(14) "getRequestBody"
  [33]=>
  string(20) "getRequestBodyStream"
}

cakephpのバグか

クラス名変えて確認

$ ls -la lib/Cake/Network/Http/
合計 72
drwxr-xr-x 2 atsushi-kambayashi atsushi-kambayashi  4096 2012-09-09 18:13 .
drwxr-xr-x 4 atsushi-kambayashi atsushi-kambayashi  4096 2012-09-01 10:28 ..
-rw-r--r-- 1 atsushi-kambayashi atsushi-kambayashi  1754 2012-09-01 10:28 BasicAuthentication.php
-rw-r--r-- 1 atsushi-kambayashi atsushi-kambayashi  3262 2012-09-01 10:28 DigestAuthentication.php
-rw-r--r-- 1 atsushi-kambayashi atsushi-kambayashi 10564 2012-09-09 17:51 HttpResponse.php
-rw-r--r-- 1 atsushi-kambayashi atsushi-kambayashi 29381 2012-09-09 18:13 HttpSocket.php

HttpSocketに使用するレスポンスクラスの名称があるので変更

/**
 * Response classname
 *
 * @var string
 */
    public $responseClass = 'CakeHttpResponse'; // 元はHttpResponse

同ディレクトリにクラスコピーして内部のクラス名を変更

$ cp lib/Cake/Network/Http/HttpResponse.php lib/Cake/Network/Http/CakeHttpResponse.php 

/**
 * HTTP Response from HttpSocket.
 * 
 * @package       Cake.Network.Http
 */
class CakeHttpResponse implements ArrayAccess { 

メソッド名出力外して確認

とりあえずページ情報はとれた
f:id:kambayashi:20120909183032p:plain

cocos2d-x タッチイベント取得

概要

  • タッチイベントを取得してゲーム中で使用する

ブランチ「develop/multi-scene-stack」をベースにする

  • 前回サンプルに追加実装した

タッチイベントコールバックをオーバーライド

  • cocos2d-xのクラスリファレンスを見るとタッチイベント用関数の仮想関数があるのでそれをアプリ用ヘッダでも宣言する
    void registerWithTouchDispatcher();
    bool ccTouchBegan( cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent );
    void ccTouchEnded( cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent );

タッチイベント実装

  • cpp側でオーバーライドした関数の実装を行う
    • http://dummyimage.com/ で画像つくってボタンを押したら画像がかわるようにする
    • CCSpriteのオブジェクトをメンバ変数で保持してるようにしているが省略
bool Title::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
    this->mSprite->initWithFile("background_touch_began.png");
    
    return true;
}

void Title::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
    this->mSprite->initWithFile("background_touch_end.png");
}

タッチイベントをとるオブジェクトの設定

void Title::registerWithTouchDispatcher()
{
    //CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,-129,true);
    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,-127,true);
}

タッチイベントの有効化

  • デフォルトでも有効かもしれないが一応initの中で呼んどく
    // enable touch event
    this->setTouchEnabled(true);

動かす

f:id:kambayashi:20120820003851p:plainf:id:kambayashi:20120820003852p:plain

cocos2d-x 別シーンに行って元のシーンに戻る

概要

  • 前回のサンプルでは切り替えたら前のシーンには戻れなかったが、ポップアップメニューや設定画面など、完了したら元の画面に戻りたい画面を作る

scene切り替え処理を変更する

  • TitleSceneのreplaceSceneは完全にシーンを置き換える処理だったが、pushSceneにするとシーンのスタックに積まれる

TitleScene.cpp

void Title::menuChangeScene(CCObject *pSender)
{
    //CCDirector::sharedDirector()->replaceScene( HelloWorld::scene());
    CCDirector::sharedDirector()->pushScene(HelloWorld::scene());
}

前のシーンに戻る

  • 子として作ったHelloWorldから前のTitleSceneに戻る処理を作る
    • とりあえず終了ボタンを押した時の処理を戻る機能にして確認してみる

HelloWorld.cpp

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    /*
    CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
     */
    CCDirector::sharedDirector()->popScene();
}

前のシーンに戻るボタンを作る

f:id:kambayashi:20120818184526p:plain