ポン酢まいるど開発記

開発のことから、ITにまつわることの感想まで、マイルドに書きます

AR Studioでサンシャイン池崎になってクラウドとくっつけた話

なぜサンシャイン池崎に?

Facebook AR Studioワークショップ&ハッカソンに行ってきました。
お題として提示されたのが、今回の話題のfacebook AR Studio! ARを使ったエフェクトや表現を作成できるツールです!

本当はイケメンになるつもりだったのですが、"イケメンとは..." を突き詰めている間に池崎がフィットした次第です。 ARとあって、顔の表面にオブジェクトを貼り付けた上で動きを追従する優れもの。。。こんな感じ↓で貼り付けられます。

f:id:accelerk:20171114222044p:plain

たまたま貼り付けたサンシャイン池崎の顔の比率がぴったりでしたねw 顔のフィット具合の検証に関しては、以下リンクに譲ります。

hiroga.hatenablog.com

池崎とクラウドをくっつけて通信する

さて、本題です。ソーシャル要素を考えると、サーバー側と通信してデータを取ってきたいという欲が出てきます。 AR Studioは動きをつけたり、エフェクトを細かく制御するのは Javascriptを使うことになります。

ただし、制約事項としては以下2点を気に留めておきましょう。 1. Node.jsやブラウザのJSのような XMLHttpRequestやNPMを直接使えるわけではない 2. モジュール分割しづらい

データを取得する場合は、Networking Classの fetch メソッドを使えばOK。(中身は JSのfetch APIを呼んでいるみたいです)

[Networking Class]
https://developers.facebook.com/docs/camera-effects/reference/networking_module/networking_class

今回のハッカソンでは、以下のようにDB(今回はIBM CloudのCloudant NoSQL DB)からデータを引っ張る形にしました。 バックエンドはNode-REDサーバーを立ててCloudantにアクセスするAPIを叩く構成です。(Node-REDやCloudantの話は今回は割愛します)

// 表情のオブジェクトを取得する
const yeah = Scene.root.find('ikevoice');

// get neta serif url of Cloudant searching by id
function getNetaUrl(_id) {
    return "https://${bluemix-app-name}.mybluemix.net/neta?_id=" + _id;
}

// DBから取得したネタセリフをオブジェクトに書き込む
function fetch_neta(url) {
    Networking.fetch(url)
    .then(function (result) {
        if (result.status >= 200 && result.status < 300) {
            const neta_serifu = result.data.neta;
            yeah.text = neta_serifu;  // ここでセリフを yeah というテキストオブジェクトにテキストを書き込む
            D.log("Fetch succeeded!!");
        } else {
            D.log('There was an error: ' + result.status);
            yeah.text = 'Error retrieving data';
        }
    });
}

// 顔を後ろに倒した時のイベントを登録
// すごく直感的なメソッド!!
FaceGestures.isLeanedBack(face).monitor().subscribe((e) => {
    if (e.newValue) {
        if (judgeOrder(3)){
            ikezakiSwitch[3] = true
            saaaay('warai2');
        } else {
            allReset()
        }
        yeah.hidden = false;
        fetch_neta(getNetaUrl('0004'));  // '0004'のセリフをDBから取ってくる
        // driver.start();
    } else {
        // driver.end();
        yeah.hidden = true;
    }
});

注意すべきは、2017/11/12現在で HTTPのGETしか使えないこと。本格的に通信するならば、websocket使えるといいんだどなー...
今回はこっちから値を渡してDBに格納するフローもあったので、ハッカソンでは GET でAPIを叩く→ 叩いたAPIでパラメータを渡すPOSTのAPI叩く→ 結果を返す という手段をとりました。こうすればCRUD処理を実装できますね(๑ᴖ◡ᴖ๑)

[Node-RED側の実装例] f:id:accelerk:20171114224318p:plain

まとめ以上!

ログアウトしてもSFTPでファイル転送させるやり方

やべえ...PCのバッテリーも尽きそう(ThinkPadいわく、残り5分)なのに、SFTP転送に30分かかる処理やんなきゃ...そんなときに調べたことの備忘録です。

やりたいこと

  • ターミナルを閉じてもSFTPの転送を実施する
  • なるべく対話処理をしない(バッテリーのライフは危機的じょうきょうだからね!)
  • 失敗しても叩くコマンドを少なく再実行可能にしたい

やったこと

  1. nohup ... でターミナルを閉じてもプロセスがキルされないようにする。
  2. 1のnohupつきでSFTP転送のコマンドを実行 nohup sftp -o "batchmode no" -b sftp_to_hoge ponz@aaa.bbb.ccc.ddd
  3. Ctrt + Z で処理を中断
  4. bg (プロセス番号) でバックグラウンドに回す

それぞれ何をやっているか、具体的に分解します。

1. プロセスをキルされないようにする

ターミナルをそっと閉じると、実行中のプロセスは閉じた瞬間に終了します。(MySQLコマンドみたいに裏で流れ続けるものもあるけど)
プロセスを終了させないための、nohup コマンド。肝としては、コマンドの最後に & をつけないこと。 これをつけてしまうといきなりバックグラウンドに処理が回って、パスワード入力できないのね。


2. SFTP転送のコマンド実行

webkaru.net

今回の肝の部分。上のリンクにもある通り、オプション付きで実行します。

-b ... このオプションの後に、処理するコマンドを記述することで、ファイルからコマンドを叩ける。いろんなページには .bat 拡張子で書かれたものを実行しているみたいだけど、拡張子なしでもいけた。

$ ls -1 /home/ponz/targets/*.csv
ponz_team.csv
ponz_workdays_2017.csv
ponz_worktime.csv

$ cat sftp_to_hoge
lcd /home/ponz/targets/
cd /mnt/hoge/datas/csv/
put *.csv
quit

-o ... 実行する環境によっては、Permittion denied と処理を続行できない場合がある。明示的にバッチ処理を行うことを宣言するため batchmode no とする。(バッチ処理なのに、batchmode no とか気持ち悪い...)

コマンド叩いてパスワードを求められたら、入れてEnterでOK。


3. 処理を中断

説明不要の、処理中断。jobs と叩くと「一時停止」となっているはず。

$ jobs
[1]+  Stopped (tty output)    nohup sftp -o "batchmode no" -b sftp_to_hoge ponz@aaa.bbb.ccc.ddd

4. 中断した処理をバックグラウンドに回す。

jobs で表示されていたジョブの番号を確認してから、bgコマンドでバックグラウンドに回してあげる。 もう一度 jobs でプロセスを確認してあげれば、バックグラウンドを表す & が勝手についているはず!

$ bg 1
$ jobs
[1]+  Running    nohup sftp -o "batchmode no" -b sftp_to_hoge ponz@aaa.bbb.ccc.ddd &

もうちょいスマートなやりかた

完全に対話処理をなくすなら、

  • 秘密鍵ファイル(identity)を置いて、-i オプション実行
  • expect コマンドで想定される標準出力に合わせてパスワード入力処理をバッチファイルに書く

どちらかでやればいいはず。 シェル化するならば、expect で書いてあげたほうがいいかも。

参考

d.hatena.ne.jp

qiita.com

sedとawkでテキスト処理を楽にした話

社内の勉強会で シェルの勉強という題目でsedawkを学んだので、備忘録。

sed

受け取った入力をフィルタリングして返す。特に置換・マッチングが得意。
Vimの文字列置換方法は知ってたけど、ツールとしてのsedは同じような記法でいける。

基本的な使い方

$ echo "ponzponz" | sed 's/z/ZZ/'
ponZZponz

sed 's/(置換元の文字)/(置換後の文字)/' の書き方をすればOK。
ただ、この書き方だとヒットした最初の文字だけ置換する。ヒットした全ての文字を置換したいときは、最後の/の後にgをつければOK。

$ echo "ponzponz" | sed 's/z/ZZ/g'
ponZZponZZ  #後ろの文字も置換された!

上の例だと全てechoで返された文字列を置換したけど、実際に使う場面だとファイルの中身に対して行うことが多いでしょうね。
この場合は置換の命令の後ろにファイル名を書いてあげる。 ちなみにこのやり方だと元ファイルが上書きされることはないです。

$ cat riders.txt
Kuuga, 2000/01/30, 49
Blade, 2001/01/28, 51
Ryuki, 2002/02/03, 50
555, 2003/01/26, 50

$ sed 's/Blade/Agito' riders.txt
Kuuga, 2000/01/30, 49
Agito, 2001/01/28, 51  <- マッチしたものだけ置換されている
Ryuki, 2002/02/03, 50
555, 2003/01/26, 50

複数条件を一気にマッチングさせたい場合は -e オプションをつければいいらしいが、横に長くなってめんどいので条件をファイルに外だし可能。

# 全てディケイドにする置換条件
$ cat onore_dicade
s/Kuuga/Dicade/
s/Blade/Dicade/
s/Ryuki/Dicade/
s/555/Dicade/

# 全てディケイドに
$ sed -f onore_dicade riders.txt
Dicade, 2000/01/30, 49
Dicade, 2001/01/28, 51
Dicade, 2002/02/03, 50
Dicade, 2003/01/26, 50

awk

sedと同じテキスト処理ができる。構造を持ったテキスト(CSV, TSVとか)ならばsedよりもawkで処理した方が楽。

基本的な使い方

$ awk '/Ryuki/ { print $1 }' riders.txt
Ryuki, 2002/02/03, 50

awk '(マッチング条件) (アクション)' (インプットファイル名) と書けばOK。
デフォルトで空白区切りで行を認識して、$n でn番目の要素を取得できる。もし区切り文字を変更したい場合は -Fオプションをつけてあげる。

# 1月始まりのライダー番組を話数と一緒に出す
$ awk -F ',' '/01/ { print $1, "全(", $3, ")話"}' riders.txt 
Kuuga 全( 49 )話
Blade 全( 51 )話
555 全( 50 )話

使い所

今の所、簡単な置換はsed、ガリガリパターンマッチングしてテキスト編集するならawk使う。
ログファイル解析や、バッチ・Excelで処理する時の下準備に使えそう。

勉強会で話してたときは、パイプでsortuniqで並び替えやら重複削除すれば傾向の把握できるねーと盛り上がってた。
ただ、数百万行になるファイルを扱う場合は、headで数行で試してからsed/awkでテキスト処理かけた方が効率良さそう。。。

個人的には、Javaとかでバッチ処理する時の前処理に使いたい。
仕事でJavaバッチ使った時に、
数百万行のCSVから全てのテキスト読み込み→編集・ソート・重複削除とか処理→出力or別のバッチに渡す... こんなことやってパフォーマンスが御陀仏になったことがあったから、
下準備としてsed/awkで必要な情報をある程度絞ってからJavaバッチに渡すといったことができるとJava側もシンプルに処理できなと思った次第。


備忘録ここまで。