Hatena::ブログ(Diary)

Memo

2014-07-27

[][] socket.io-go-emitter を試してみる

SocketIO のサーバー側が Node.js で以下のようなコード。

var io = require('socket.io').listen(9000);
var logger = require('./logger');
var redis = require('socket.io-redis');

io.adapter(redis({ host: 'localhost', port: 6379 }));

io.sockets.on('connection', function (socket) {
  logger.info('Connected from' + socket.id);

  socket.on('disconnect', function () {
    logger.info('disconnect');
  });
});

logger.info('Start Socket.IO server');
logger.info('Listening localhost:9000');

ブラウザ側。

var socket = io.connect('http://localhost:9000');
socket.on('msg', function (data) {
  console.log(data);
});

クライアント側の Golang なコード。

package main

import (
    "github.com/yosuke-furukawa/socket.io-go-emitter"
)

func main() {
    emitter, _ := SocketIO.NewEmitter(&SocketIO.EmitterOpts{
        Host: "127.0.0.1",
        Port: 6379,
    })
    emitter.Emit("msg", "I love you!!")
}

Golang を go run client.go として実行すると、ブラウザ側に I love you!! というメッセージが表示された。

てっきり一回 Node.js 側(上のコード方)で受信して、そこからブラウザにブロードキャストするもんかとおもってたけど、ちょっと動きが違って少しビックリした。


今までこういう事をやろうとすると、maccman/juggernaut ? GitHub を使ってたけど、juggernaut は DEPRECATED になってたので、SocketIO 自体でサポートしてくれて良かった。


最初 Node.js の代わりに Golang の SocketIO 1.0 を使おうと思ったが、CORS はデフォルトでサポートしてないみたいなので、とりあえず Node.js で試した。

CORS が必要なのはメインで動作させるのが Flask で SocketIO は別ポートで動かしたいから。

2014-07-26

[] CentOSsudo yes でエラー

メモ。

Ansible で CentOS6.4 に対して以下のコマンドを実行しても転送されない。

hosts/development

[development]
192.168.1.10
$ ansible-playbook -i hosts/development site.yml -k -c paramiko
PLAY [development] ************************************************************ 
GATHERING FACTS *************************************************************** 
<192.168.1.10> REMOTE_MODULE setup

これでタイムアウト

サーバー側に /var/log/secure を見ると、sftp を使おうとしてる。

というわけで、

ansible.cfg scp_if_ssh = True と transport = ssh を追加。

[ssh_connection]
ssh_args = -o ForwardAgent=yes
scp_if_ssh = True

[defaults]
host_key_checking = False
transport = ssh
$ ansible-playbook -i hosts/development site.yml -k -c ssh -vv
PLAY [development] ************************************************************ 
GATHERING FACTS *************************************************************** 
<192.168.1.10> ESTABLISH CONNECTION FOR USER: ansible_user
<192.168.1.10> REMOTE_MODULE setup
<192.168.1.10> EXEC ['ssh', .....

接続は確立されたけど、今度は sudo が正しく動作してないよう。

Ansible 1.2.2 hangs on playbook with sudo: yes ? Issue #3881 ? ansible/ansible ? GitHub

--ask-sudo-pass

を付けろと。


というわけで、最終的に以下のコマンドで正しく動作した。

$ ansible-playbook -i hosts/development site.yml -k -c ssh -vv --ask-sudo-pass

2014-07-23

[] Node.js の logger

どれ使えばいいのか良く分からない。

log4js を使えばいいのか。

適当にググったら winstone ってのを見つけたので試してみる。


var env = process.env.NODE_ENV || 'dev';
var winston = require('winston');
 
winston.setLevels(winston.config.syslog.levels)
 
if (env !== 'dev') {
  winston.remove(winston.transports.Console);
}
 
var customColors = {
  trace: 'white',
  debug: 'green',
  info: 'green',
  warn: 'yellow',
  crit: 'red',
  fatal: 'red'
};
 
var logger = new (winston.Logger)({
  colors: customColors,
  levels: {
    trace: 0,
    debug: 1,
    info: 2,
    warn: 3,
    crit: 4,
    fatal: 5
  },
  transports: [
    // Console.
    new (winston.transports.Console)({
      level: 'trace',
      colorize: true,
      timestamp: true
    }),
    // File.
    new (winston.transports.File)({
      filename: './logs/node.log',
      level: 'info',
      timestamp: true,
      json: false,
      maxsize: 100000,
      maxFiles: 5,
    })
  ]
});
winston.addColors(customColors);
 
module.exports = logger;

app.js

var logger = require('./logger');
logger.trace('trace');
logger.debug('debug');
logger.info('info');
logger.warn('warn');
logger.crit('crit');
logger.fatal('crit');
$ node app.js
2014-07-23T15:48:33.023Z - trace: trace
2014-07-23T15:48:33.026Z - debug: debug
2014-07-23T15:48:33.027Z - info: info
2014-07-23T15:48:33.027Z - warn: warn
2014-07-23T15:48:33.028Z - crit: crit
2014-07-23T15:48:33.028Z - fatal: crit

trace とか debug の文字の所に色が付いて表示された。

logs/node.log にもちゃんとログが出力された。

時間が +9:00 されてない感じがするが、とりあえずこれを使ってみよう。

2014-07-12

[][] VimGolang を書く時の補完の設定

Golang 付属(最近 vim-jp でもホストされるようになった) Vim の設定で C-x C-o で補完候補を選べる。

neocomplecache や neocomplete を使えばなにも気にしなくて良いのかもしれないけど、Golang の場合、補完のリストを出すのが遅い。

なので、. を打つ度に待たされるのは嫌なので、Golang の場合はネオコンを使わずに手動で補完を出す事にした。


ただ、C-x C-o で補完した場合、補完リストが表示されてかつ最初の候補が選択している状態になる。

これが嫌だ。

補完候補を自分で入力して絞り込みたい。

ということで、~/.vim/after/ftplugin/go.vim に書いた。

ちょっと幸せになれた!

ありがとうございます!!


追記

とのこと。

2014-07-04

[] また Flask-Injector の仕様変更

Injector の仕様変更 - Memo


また変更があった。

$ python manage.py runserver
/path/to/virtualenvs/project/lib/python3.4/site-packages/flask_injector.py:146: UserWarning: init_app and post_init_app are deprecated in favour of FlaskInjector. Please consult README for details.
  "init_app and post_init_app are deprecated in favour of FlaskInjector. "

またかと思ったけど、まぁ Warning を出してくれるだけありがたい。

-from flask.ext.injector import init_app, post_init_app
+from flask.ext.injector import FlaskInjector
@@ -229,8 +229,7 @@ def configure_injector(app, modules=None):
 
-    injector = init_app(app=app, modules=modules)
-    post_init_app(app, injector)
+    FlaskInjector(app=app, modules=modules)

こんな感じで修正

まぁシンプルになった。

2014-07-01

[] pluginbase が便利そう。

@mitsuhiko 先生の新作の pluginbase が便利そうというお話。


Python は他の Python なファイルをモジュールとして動的に読み込む場合は import があるから少し面倒。

例えば今作ってる Flask を使ったアプリケーションで、WSGI ミドルウェアを読み込む時には以下の様にしている。

def configure_middlewares(app):
    middlewares = app.config['MIDDLEWARES']
    if not isinstance(middlewares, tuple):
        middlewares = (middlewares,)
    for middleware in middlewares:
        target = middleware.split('.')
        module = '.'.join(target[0:-1])
        name = target[-1]
        klass = getattr(__import__(module, fromlist=[name]), name)
        app.wsgi_app = klass(app)

app.config['MIDDLEWARES'] には、WSGI ミドルウェア*1を格納しているパスを与えて、ファイル名からを使って、__import__() と getattr() を使っている。

klass(app) としている通り、クラスという制約を課して読み込んでいる*2


こういう風に、自分で頑張る必要がある。

現状これで困ってないけど、もっとシンプルにプラグインを読み出すフレームワークpluginbase


ディレクトリ構成はこんな感じ。

.
├── app.py
└── plugins
    ├── __init__.py
    ├── bar.py
    └── foo.py

app.py がエントリポイントで、plugins は以下のような感じのファイル。

foo.py

# -*- coding: utf-8 -*-
def say(s):

    return 'hello {0}'.format(s)

bar.py

# -*- coding: utf-8 -*-
class Bar(object):
    def __init__(self):
        print('init')
    
    def say(self, name):
        return 'say {0}'.format(name)

foo.py は関数定義、bar.py はクラスの定義をした。


app.py はこんな感じ。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from functools import partial
from pluginbase import PluginBase

here = os.path.dirname(os.path.abspath(__file__))
get_path = partial(os.path.join, here)


if __name__ == '__main__':
    plugin_base = PluginBase(package='plugins')
    plugin_source = plugin_base.make_plugin_source(searchpath=[
        get_path('plugins')
    ])

    my_plugin = plugin_source.load_plugin('foo')
    ret = my_plugin.say('hoo')
    print(ret)
    
    my_plugin_class = plugin_source.load_plugin('bar')
    ret = my_plugin_class.Bar().say('fooo')
    print(ret)

Plugin となるディレクトリのパスとディレクトリ名を設定して、ファイル名を呼び出すとモジュールがロードされる。

関数の場合はそのまま、関数オブジェクトが呼べる。

クラスの場合は、クラス名が呼べるので、インスタンスを生成すれば行ける。


実行結果

$ python app.py
hello hoo
init
say fooo

お手軽!!

*1:たとえば、HTTP の method のリライトを行う奴とか

*2:たまたま自分の例がそうなだけで、関数も行ける

2014-06-26

[] Ansible が Vagrant に接続できなくなった

メモ。

ちょっと試したい事があったので、Ansible playbook をローカルに建てた Vagrant に対して実行したかった。

いつも通り、以下のコマンドを打ったら、エラーになった。

$ ansible-playbook -i hosts vagrant.yml -k -c paramiko -vvv
SSH password: 

PLAY [vagrant] **************************************************************** 

GATHERING FACTS *************************************************************** 
<127.0.0.1> ESTABLISH CONNECTION FOR USER: vagrant on PORT 2222 TO 127.0.0.1
fatal: [vagrant] => {'msg': "FAILED: ('127.0.0.1', <paramiko.rsakey.RSAKey object at 0x10a903450>, <paramiko.rsakey.RSAKey object at 0x10a8f4650>)", 'failed': True}

つい、この間まで動いていたのに…。


しばらく Ansible を実行しようとした VM とは 違う VM を起動して作業をしていた。

で、こいつの接続先やポートが今実行しようとしたものとかぶってた模様…。

なので、ansible.cfg に以下の設定を加えたらいけた。

[defaults]
host_key_checking = False

Getting Started — Ansible Documentation