Quantcast
Channel: Big Sky
Viewing all 121 articles
Browse latest View live

Go言語でWebAppの運用に必要なN個のこと

$
0
0
golang - Go言語でWebAppの開発に必要なN個のこと - Qiita [キータ]

http://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies アプリケーションサーバ 標準パッケージの ne...

http://qiita.com/tenntenn/items/b8b27e32c28f7569f41a
tenntenn さんに開発版を書いて貰ったので運用編を書こうかと思った。
なお、以下のプロダクトは全て golang で書かれているが、ruby や perl のアプリケーションを運用する際にも使える。

リバースプロキシ

まずはリバースプロキシ。フロントは nginx にしてパスによりアプリを切り分ける。(別に直でもいいけど)
mattn/gorem - GitHub
https://github.com/mattn/gorem
ゴーレムと読みます。インストールは以下の様にして行う。
$ go get github.com/mattn/gorem
設定ファイルは以下の様に config.json を用意する。
{
  "mattn": {
    "address""127.0.0.1:11006",
    "entries": [
      { "path""/app1/""backend""http://localhost:10086" },
      { "path""/app2/""backend""http://localhost:10087" },
      { "path""/",      "backend""/home/mattn/tmp/blog/_site" }
    ]
  }
}
127.0.0.1:11006がサーバのポート。これにより /app1/へのリクエストが http://localhost:10086//app2/へのリクエストが http://localhost:10087/へ転送される。 /へのリクエストは、生成した静的コンテンツ(ここでは jekyll で生成したファイル)を指す。
なお、gorem は /app1/fooというリクエストを http://localhost:10086/app1/fooではなく http://localhost:10086/fooに転送するので、もし http://localhost:10086/app1/fooに転送したい場合は
{
  "mattn": {
    "address""127.0.0.1:11006",
    "entries": [
      { "path""/app1/""backend""http://localhost:10086""use_path"true },
      { "path""/app2/""backend""http://localhost:10087" },
      { "path""/",      "backend""/home/mattn/tmp/blog/_site" }
    ]
  }
}
の様に use_pathを指定する。また CGI が使いたい場合は
{
  "mattn": {
    "address""127.0.0.1:11006",
    "entries": [
      { "path""/app1/""backend""http://localhost:10086""use_path"true },
      { "path""/app2/""backend""http://localhost:10087/foo.cgi""cgi"true },
      { "path""/",      "backend""/home/mattn/tmp/blog/_site" }
    ]
  }
}
の様に cgi設定する。設定は複数記述する事ができ
{
  "mattn": {
    "address""127.0.0.1:11006",
    "entries": [
      { "path""/app1/""backend""http://localhost:10086""use_path"true },
      { "path""/app2/""backend""http://localhost:10087/foo.cgi""cgi"true },
      { "path""/",      "backend""/home/mattn/tmp/blog/_site" }
    ]
  },
  "thinca": {
    "address""127.0.0.1:11008",
    "entries": [
      { "path""/app1/""backend""http://localhost:10088""use_path"true },
      { "path""/app2/""backend""http://localhost:10089/foo.cgi""cgi"true },
      { "path""/",      "backend""/home/thinca/tmp/blog/_site" }
    ]
  }
}
の様にも書ける。動作させたまま設定を読み込みなおす場合は、gorem のプロセスに SIGHUP を送る。
$ kill -HUP 12345
上記の設定で thinca だけ再読み込みしたい場合は
{
  "mattn": {
    "address""127.0.0.1:11006",
    "entries": [
      { "path""/app1/""backend""http://localhost:10086""use_path"true },
      { "path""/app2/""backend""http://localhost:10087/foo.cgi""cgi"true },
      { "path""/",      "backend""/home/mattn/tmp/blog/_site" }
    ]
    "flagfile""/tmp/gorem.mattn"
  },
  "thinca": {
    "address""127.0.0.1:11008",
    "entries": [
      { "path""/app1/""backend""http://localhost:10088""use_path"true },
      { "path""/app2/""backend""http://localhost:10089/foo.cgi""cgi"true },
      { "path""/",      "backend""/home/thinca/tmp/blog/_site" }
    ],
    "flagfile""/tmp/gorem.thinca"
  }
}
の様に設定しておき
$ touch /tmp/gorem.thinca
とすれば thinca だけ再読込される。

プロセスマネージャ

ruby に foreman というツールがある。Procfile で指定したプロセス情報と .env という環境変数情報を参照してプロセスを起動する。 しかし軽量ではない。そこで私は goreman というツールを使っている。
mattn/goreman - GitHub
https://github.com/mattn/goreman
インストールは以下の様にして行う。
$ go get github.com/mattn/goreman
Procfile の書き方は foreman と同じ。
gorem: /home/mattn/dev/gorem/gorem -c /home/mattn/dev/gorem/config.json
my_app1: ruby /home/mattn/dev/my_app1/web.rb
my_app2: ruby /home/mattn/dev/my_app2/web.rb
ここで先ほどの gorem も一緒に起動しておく。例えば上記の gorem の設定だと /app1 を my_app1 に、/app2 を my_app2 に振り分ける。 起動は Procfile のあるディレクトリで
$ goreman start
とすればいい。単独で起動停止したい場合は別の端末で
$ goreman run stop my_app2
$ goreman run start my_app2
$ goreman run restart my_app2
とする。内部で RPC を使っているがポートを変えたい場合は環境変数 GOREMAN_RPC_PORT で変更する。
memcached 等も一緒に起動しておくと良い。

Github インテグレーション

github に push したら勝手にデプロイして欲しい。
mattn/gost - GitHub
https://github.com/mattn/gost
インストールは以下の様にして行う。
$ go get github.com/mattn/gost
起動は goreman の Procfile に含めて起動しておく。
gorem: /home/mattn/dev/gorem/gorem -c /home/mattn/dev/gorem/config.json
my_app1: ruby /home/mattn/dev/my_app1/web.rb
my_app2: ruby /home/mattn/dev/my_app2/web.rb
gost: /home/mattn/dev/gorem/gost -c /home/mattn/dev/gost/config.json
また外部からのアクセスに対してリバースプロキシ経由でアクセスされる様に gorem の設定にも追加する。
{ "path": "/deploy/", "backend": "http://localhost:11613" },
※設定は一部

gost の設定ファイルは以下の様に記述する。
{
  "addr""127.0.0.1:11613",
  "apps": {
    "wikipedia-lingrbot": {
      "proc""wikipedia_bot",
      "path""/home/mattn/dev/wikipedia_bot/",
      "build_command""go build",
      "test_command""go test"
    },
    "momochan": {
      "proc""momochan",
      "path""/home/mattn/dev/momochan/"
    }
  }
}
あとは github の Web hook を上記の /deploy/に仕向けて完成。 gost は Web hook のペイロードを受け取ると goreman に対して停止、git pull、起動を行う。もしビルドが必要であれば上記の様に build_commandを指定する。その他 test_commandrelease_commandもある。 上記の wikipedia-lingrbotは github のリポジトリ名、proc で指定する wikipedia_botは goreman の Procfile に書いた proc 名となる。 path はそのリポジトリがあるローカルパスを指定し、そこで git pullが行われる。なお git clone 時に git@github.comで clone してると認証が必要になるので https://github.com/ で始まる URL で clone しておく事。

Go言語でインタフェースの変更がそれ程問題にならない理由

$
0
0
golang - Go言語における埋め込みによるインタフェースの部分実装パターン - Qiita [キータ]
http://qiita.com/tenntenn/items/e04441a40aeb9c31dbaf
golang はインタフェースがマッチしているかどうかにより処理を切り分けられる。
package main

import "fmt"

type Person struct {
    FirstName string
    LastName  string
}

func (p *Person) Name() string {
    return p.FirstName + " " + p.LastName
}

func main() {
    person := &Person{"Taro""Yamada"}
    fmt.Println(person.Name())
}
メソッドを保持しているのであれば、インタフェースにアサーション出来る。
package main

import "fmt"

type Person struct {
    FirstName string
    LastName  string
}

func (p *Person) Name() string {
    return p.FirstName + " " + p.LastName
}

type Named interface {
    Name() string
}

func printName(named Named) {
    fmt.Println(named.Name())
}

func main() {
    person := &Person{"Tarou""Yamada"}
    printName(person)
}
そして実は型がマッチしているかを確認する事も出来る。interface{}にキャストした後に指定のインタフェースで型アサーションを行う。その際に戻り値の2つめにアサーションが成功したかどうかが返される。
package main

import "fmt"

type Person struct {
    FirstName string
    LastName  string
}

func (p *Person) Name() string {
    return p.FirstName + " " + p.LastName
}

type Named interface {
    Name() string
}

// パーさんは Name メソッドを持たない
type Persan struct {
    FirstName string
    LastName  string
}

func printName(named Named) {
    fmt.Println(named.Name())
}

func main() {
    person := &Person{"Tarou""Yamada"}
    named, ok := interface{}(person).(Named)
    if ok {
        printName(named)
    } else {
        fmt.Println("Person is not Named intreface")
    }

    persan := &Persan{"Tarou""Yamada"}
    named, ok = interface{}(persan).(Named)
    if ok {
        printName(named)
    } else {
        fmt.Println("Persan is not Named intreface")
    }
}
つまり例えば、ライブラリやドライバが新しいメソッドに対応しているかどうか、と言った事を動的に確認出来る様になります。
この手法はオフィシャルパッケージの database/sqlでも使われており、各ドライバが指定のインタフェースを実装しているかどうかを確認しています。
type Execer interface {
    Exec(query string, args []Value) (Result, error)
}
Exec というメソッドを持ったインタフェース Execer を用意して
if execer, ok := dc.ci.(driver.Execer); ok {
}
Execer にアサーション可能な場合だけ特別な処理を行う、という事をやっています。
C/C++ の様に依存ライブラリの特定バージョン以降でメソッドがあったり無かったりという呪縛から解き放たれる訳です。
これがリフレクション無しに出来るのは便利ですね。

Golang の channel の使い所

$
0
0
golang の特徴と言えば goroutine と channel ですが、その使いどころに悩む人もおられる様です。
goroutine は非同期に実行される処理、channel はその groutine と通信する為の仕組みと考えると分かりやすいです。
package main

import (
    "fmt"
    "time"
)

func main() {
    task := make(chan string)
    taskquit := make(chan bool)
    workerquit := make(chan bool)

    go func() {
    loop:
        for {
            select {
            case <-taskquit:
                workerquit <- true
                break loop
            case job := <-task:
                fmt.Println(job)
            }
        }
    }()

    go func() {
        for n := 0; n < 3; n++ {
            task <- fmt.Sprintf("お仕事%03d", n+1)
            time.Sleep(1 * time.Second)
        }
        taskquit <- true
    }()

    <-workerquit
}
この様に goroutine との間でキューの役割を果たします。channel はバッファを持っておりある程度の量ならばブロックする事無く goroutine と通信出来ます(バッファサイズはmakeで変更可能)。
この goroutine と channel をどの様に使うかですが、まず非同期を意識せずに主たる目的を持って処理を書きます。
  • ある処理から「お仕事」が3回投げかけられる
  • ある処理では「お仕事」の依頼を受けると逐次処理する
ここを非同期にする事でパフォーマンスアップを行います。速度面もそうですが上記の様な処理を順番に行う為には全ての「お仕事」をメモリに蓄積しておくか、「お仕事」の依頼があるたびにその処理を実行するコールバックを呼び出してやる必要があります。
しかし groutine と channel を使う事で
  • お仕事の依頼を投げる側
  • お仕事の依頼を受ける側
に処理を分割する事が出来ます。お仕事を投げる側はソケットか何かで電文を受信してパースし、チャネルに「お仕事」を投げつけます。
task <- fmt.Sprintf("お仕事%03d", n+1)
そしてお仕事を受ける側はその channel を指定して「お仕事」を受け取ります。
しかしお仕事を受ける側は、永遠にループする訳にはいけません。終了指示があれば中途半端にお仕事を処理せずに、グレースフルに終了したい物です。そこで終了用の channel を用意して、それを両方 select します。
例ではタスク登録 goroutine 終了用とワーカー終了用を用意しました。
select {
case <-taskquit:
    workerquit <- true
    break loop
case job := <-task:
    fmt.Println(job)
}
元々、別の関数で実装されていた処理というのは並列でない事はもちろんですが、多くのメモリを必要とします。さらにそれをコールバックベースの処理に作り替えると、大きくコードを壊さなければなりません。また純粋に並列ではありません。
golang の goroutine と channel を使えば、既存の処理を簡単に並列化する事が出来るのです。
今回の例では両方共に goroutine にしましたが、この目的で言えばお仕事を投げる側は goroutine でなくても構いません。
例えば Web でデータを登録し、それをバックグランドジョブとして後処理したいといった場合に、この channel の威力が発揮されるでしょう。

追記
先にワーカーが終了しないケースがあったのでコードを修正。

Golang で Treasure Data のライブラリ書いた。

$
0
0
Treasure Data の REST API をコールするライブラリを書いた。
REST API | Treasure Data

REST API The user can control Treasure Data using the public REST API. This article will explain how...

http://docs.treasure-data.com/articles/rest-api
mattn/go-treasuredata ・ GitHub
https://github.com/mattn/go-treasuredata
使い方はこんな感じ。
client := treasuredata.NewClient("TREASUREDATA-API-KEY")
job, _ := client.JobIssueHive("mydb""select * from mytable")
client.JobResultFunc(job.JobId, func(row []interface{}) error {
    fmt.Println(row)
    return nil
})
結果は JSON で貰えます。データが大量に返る場合があるのでデータ取得はコールバックで行います。error を返せば途中で抜けられます。
td フォルダにはコマンドラインツールが入っていて、クエリをコマンドラインから投げられます。
$ cd td
$ go build td.go
$ export TREASURE_DATA_API_KEY=xxxxxx
$ ./td -d mattn -q 'select * from unko'
["残念","小",{"size":"小","feel":"残念","time":"1363948092"},1363948092]
["残念","小",{"size":"小","feel":"残念","time":"1363948093"},1363948093]
["残念","小",{"size":"小","feel":"残念","time":"1363948094"},1363948094]
["残念","小",{"size":"小","feel":"残念","time":"1363948095"},1363948095]
["残念","小",{"size":"小","feel":"残念","time":"1363948096"},1363948096]
["残念","小",{"size":"小","feel":"残念","time":"1363948097"},1363948097]
["爽快","大",{"size":"大","feel":"爽快","time":"1363948098"},1363948098]
["残念","小",{"size":"小","feel":"残念","time":"1363948091"},1363948091]
["残念","小",{"size":"小","feel":"残念","time":"1363948092"},1363948092]
["残念","小",{"size":"小","feel":"残念","time":"1363948093"},1363948093]
["残念","小",{"size":"小","feel":"残念","time":"1363948094"},1363948094]
["残念","小",{"size":"小","feel":"残念","time":"1363948095"},1363948095]
["残念","小",{"size":"小","feel":"残念","time":"1363948096"},1363948096]
["残念","小",{"size":"小","feel":"残念","time":"1363948097"},1363948097]
["爽快","大",{"size":"大","feel":"爽快","time":"1363948098"},1363948098]
["残念","小",{"size":"小","feel":"残念","time":"1363948092"},1363948092]
["残念","小",{"size":"小","feel":"残念","time":"1363948093"},1363948093]
["残念","小",{"size":"小","feel":"残念","time":"1363948094"},1363948094]
["残念","小",{"size":"小","feel":"残念","time":"1363948095"},1363948095]
["残念","小",{"size":"小","feel":"残念","time":"1363948096"},1363948096]
["残念","小",{"size":"小","feel":"残念","time":"1363948097"},1363948097]
["爽快","大",{"size":"大","feel":"爽快","time":"1363948098"},1363948098]
["残念","小",{"size":"小","feel":"残念","time":"1363948091"},1363948091]
["残念","小",{"size":"小","feel":"残念","time":"1363948092"},1363948092]
["残念","小",{"size":"小","feel":"残念","time":"1363948093"},1363948093]
["残念","小",{"size":"小","feel":"残念","time":"1363948094"},1363948094]
["残念","小",{"size":"小","feel":"残念","time":"1363948095"},1363948095]
["残念","小",{"size":"小","feel":"残念","time":"1363948096"},1363948096]
["残念","小",{"size":"小","feel":"残念","time":"1363948097"},1363948097]
["爽快","大",{"size":"大","feel":"爽快","time":"1363948098"},1363948098]
毎日のウンコのサイズを treasure data に入れておいて、go-treasuredata で履歴を照会出来る様にしておけば健康管理もバッチリですね。

Golang で Jekyll のクローン作った。

$
0
0
普段 vim-jpや色んな所で jekyllを使っているのだけど、どうも遅くて困っていました。
Windows だと ruby 本体の起動も重いのに、たかだか数十ページの生成に十数秒、PCの負荷が高い時には30秒近く掛かったりしていました。
何とか出来ないかなーと思って、golang を使ってクローンを作ってみました。
mattn/jedie - GitHub

jedie - static site generator, jekyll replacement, in golang

https://github.com/mattn/jedie
インストールは以下の様に行います。
$ go get github.com/mattn/jedie
jekyll と同様にひな形の出力も出来ます。
$ mkdir mysite
$ cd mysite
$ jedie new .
markdown エンジンの変更等は出来ませんので _config.yml でのカスタマイズ性は高くないです。
テンプレートエンジンには pongo を使いました。
flosch/pongo - GitHub

pongo is a well-tested template engine which implements a Django-template -like syntax

https://github.com/flosch/pongo
django のテンプレートエンジンを真似ていますが、jekyll の liquid も良く似た構文になっています。jedie では liquid と似る様に、幾つかフィルタも追加しています。
_postsyyyy-mm-dd-title.mdというファイルを書いたら
$ jedie build
_siteに html が生成されます。for を使って site.postsをぐるぐる回したりも出来ます。
またローカルサーバを立ち上げる事も出来ます。
$ jedie serve
フォルダを監視して、変更があれば自動で変換する処理も実装しています。
細かな点で jekyll と異なる点があるかもしれませんが、僕としてはこれで十分なレベルになったので公開してみました。
ちなみに jekyll で時間が掛かっていたサイトを jedie で生成してみましたが、「フハハハハハ...」と笑みがこぼれる程に高速でした。
テンプレート記法をそれ程使っていない方であれば、jekyll から乗り換え可能かもしれません。
The Way to Go: A Thorough Introduction to the Go Programming LanguageThe Way to Go: A Thorough Introduction to the Go Programming Language
Ivo Balbaert
iUniverse / (2012-03-09)
 
発送可能時間:

Vim script は人々の生活を豊かにしなければならないッ!

$
0
0
この記事はVim Advent Calendar 2013 : ATND 7日目の記事になります。

2013年もあと少しです。今年も Vim に関する色んな話題が登場しました。
そして数多くの Vim plugin が今年も登場しました。
  • ステータスバーをスタイリッシュにするプラグイン
  • Markdownをプレビューするプラグイン
  • 正規表現をプレビューするプラグイン
  • ブラウザと通信するプラグイン
  • 補完プラグイン
  • 貴様!?まさか!
  • そのまさかだ!フハハハハハハ...
どれも凄い物ばかりでした。そして Vim 界においては日本人の活動が特に素晴らしかったと思っています。 k_takata さんの大活躍で多くのパッチが vim-jp より提出され取り込まれました。
何名かの方には Vim 7.4 のリリース後も動作検証に協力頂きましたし、Vim advent calendar 2012 は結局1年を通して記事をポストし続けてしまいましたし、vimrc読書会も毎週続けられ、Vim に関するイベントも多く開催されました。
個人的には9月に KoRoN さん、h_east さん、ytaniike さんとお好み焼きを食べに行った事も良い思い出になりました。ありがとうございました。

来年も Vim にとって良い年である事を切に願います。
さて、今年作られた Vim plugin、どれも良い物でしたが僕がいつも思う事はこんな事です。

Vim プラグインとは言え、作るからには人々の暮らしを豊かにしなければならないッ!
僕は Windows を良く使います。僕の Vim script 力で Windows ユーザを豊かにしたい、くじけそうになっている人を Vim で救いたい。モテたいと願っている青年達を Vim でモテモテにしたい。そう願って今年も新しいプラグインを作りました。
mattn/startmenu-vim - GitHub
https://github.com/mattn/startmenu-vim
StartMenu

CtrlPUniteで Windows のスタートメニューが扱えます。
これでいちいちマウスに手を伸ばしてスタートメニューをクリックし、ポチポチとツリーを展開したり検索語を入力していく必要もありません。

あえて日本語ロケールの名称で一覧していませんので、IME を使わず英名でマッチします(ショートカット名が日本語の場合は頑張って下さい)。これで Vim から Excel 等を簡単に起動出来る様になりました。
会社で Vim から Excel 起動したら、きっと同僚の眼差しも「センパイッ!すごい!」となるでしょう。
もっと豊かに、もっと豊かに...

そうだ...そうなんだ。僕のプラグインで便利になったのはプログラムの起動方法でしかないッ!Windows ユーザはそのランチャーから起動した Excel で設計書を閲覧するんだ!彼らの生活を豊かにする為には、Vim で Excel を開けなければならないんだァッ!!これはもう、Vim で Excel を見れる様にするしかない!!1
そう思って、もう一つプラグインを作りました。
mattn/excelview-vim - GitHub
https://github.com/mattn/excelview-vim
てっとりばやく言うと、Vim で Excel を閲覧出来ます。
:ExcelView Book1.xls
で表示出来ます。シート番号を指定して
:ExcelView Book1.xls 2
という開き方も出来ます(この辺は、今後もしかしたら変更するかもしれません)。
excelview1
こんな Excel ファイルであれば
excelview2
こう表示されます。
xlsx 形式(Excel 2007形式)のファイルしか読めないです。今後、もしかしたら CSV には対応するかもしれません。実行には webapi-vimが必要です。
ちなみに Pure Vim script の XML パーサでこんな事やってます。
let doc = webapi#xml#parse(xml)
let rows = doc.childNode("sheetData").childNodes("row")
let cells = map(range(1256)'map(range(1,256), "''''")')
let aa = char2nr('A')
for row in rows
  for col in row.childNodes("c")
    let r = col.attr["r"]
    let nv = col.childNode("v")
    let v = empty(nv) ? "" : nv.value()
    if has_key(col.attr, "t") && col.attr["t"== "s"
      let v = ss[v]
    endif
    let x = char2nr(r[0]) - aa
    let y = matchstr(r, '\d\+')
    let cells[y][x+1= v
  endfor
endfor
今の所、制限事項として 256x256 のデータしか表示出来ません。それ以上のデータを読み込むとエラーが発生します(改良の予定です)。

これでとても豊かになりました。ssh でサーバにログインしている開発者が Excel で仕様書を送りつけられても椅子を投げる事も無くなると信じています。

良い年末をお過ごし下さい。
実践Vim 思考のスピードで編集しよう!実践Vim 思考のスピードで編集しよう!
Drew Neil
アスキー・メディアワークス / ¥ 2,940 (2013-08-29)
 
発送可能時間:通常2~4週間以内に発送

Vimテクニックバイブル ~作業効率をカイゼンする150の技Vimテクニックバイブル ~作業効率をカイゼンする150の技
Vimサポーターズ
技術評論社 / ¥ 3,129 (2011-09-23)
 
発送可能時間:在庫あり。

Golang で PubSub 出来る go-pubsub を書いた。

$
0
0
Golang ってネットワークを扱うのが凄く楽で色んな物が作りたくなるんだけど、いつも pubsub っぽいのが欲しくなって毎回作ってる気がしたので汎用的に扱えるインタフェースを作った。
mattn/go-pubsub - GitHub
https://github.com/mattn/go-pubsub
使い方は簡単で、まず subscribe 側はある型を引数に持つコールバックで Sub を呼び出す。
ps := pubsub.New()
ps.Sub(func(i int) {
    fmt.Println("int subscriber: ", i)
})
そして publish 側はある型を指定して Pub を呼び出す。
ps.Pub(1)
Pub された値と同じ型の引数を持つ subscriber のみがメッセージを受け取れるという仕組み。構造体も渡せるので複雑なメッセージ内容もOK。
ちなみに unsubscribe は Sub に渡したコールバック関数を Leave に渡すか、コールバック内で
ps.Sub(func(f *foo) {
    fmt.Println("foo subscriber: ", f.bar)
    ps.Leave(nil)
})
この様に nil を与えると呼出中のコールバックが unsubscribe されます。 簡単に chat を作ってみました。
package main

import (
    "bufio"
    "github.com/mattn/go-pubsub"
    "log"
    "net"
    "strings"
)

func main() {
    ps := pubsub.New()

    l, err := net.Listen("tcp"":5555")
    if err != nil {
        log.Fatal(err)
    }
    log.Println("Listing", l.Addr().String())
    log.Println("Clients can connect to this server like follow:")
    log.Println("  $ telnet server:5555")
    for {
        c, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }
        go func(c net.Conn) {
            buf := bufio.NewReader(c)
            ps.Sub(func(t string) {
                log.Println(t)
                c.Write([]byte(t + "\n"))
            })
            log.Println("Subscribed", c.RemoteAddr().String())
            for {
                b, _, err := buf.ReadLine()
                if err != nil {
                    log.Println("Closed", c.RemoteAddr().String())
                    break
                }
                ps.Pub(strings.TrimSpace(string(b)))
            }
            ps.Leave(nil)
        }(c)
    }
}
やばい。簡単すぎる。

高速なビルドシステム「ninja」

$
0
0
ninjaいままで「SCons とか gyp とか、なんで C++ のシステムに python 入れなあかんねん」とか「せっかく python 入れたのに windows でビルドするには cygwin 版が必要とかいい加減にしろ」とか色んな事があったのですが、ninja を使う事で悩みが解消するかもしれません。
Ninja, a small build system with a focus on speed

Ninja is a small build system with a focus on speed. It differs from other build systems in two majo...

http://martine.github.io/ninja/

如何にも外国人ウケしそうなプロジェクト名です。
ninja は chromium ブラウザの開発者が現行のビルドシステムに嫌気をさして作り始めたビルドシステムです。これまでちょっとしたファイルの変更であってもビルド開始までに10秒掛かっていたのが1秒以下になるとの事です。ninja のウリは高速であり、ゴールも高速。configure の様な依存から解決するのではなく、現行のファイル構成からソースレベルの依存情報を解決します。
主に以下の様な目標をかかげています。
  • 高速なインクリメンタルビルド
  • コードのビルド方法を記述する為のポリシーをなるべく小さく
  • 正しく依存を解決
ちなみに ninja は Windows でも簡単にビルド出来ます。mingw を使う場合は python bootstrap.py --platform=mingwとすればok。
ninja は build.ninja というファイルを読み込みます。記述方法は Makefile に似ています。
build.ninja には rule という形でコマンドを定義し、あとは依存関係のみを記述します。例えば Windows で foo.c から foo.o を作り、foo.exe を生成する build.ninja を書くとすれば以下の様になります。
cflags = -Wall

rule ld
  command = gcc $ldlags $in -o $out
rule cc
  command = gcc $cflags -c $in -o $out

build foo.o: cc foo.c
build foo.exe: ld foo.o
depfile にも対応しており、gcc -Mと連携して簡単に依存関係が記述出来ます。
rule cc
  depfile = $out.d
  command = gcc -MMD -MF $out.d [other gcc flags here]
色んな所で速度比較が行われている様ですが、ninja の特徴はコマンドを実行してからビルドが開始するまでのオーバーヘッドの短縮にある様です。いずれ chromium のビルドに使われ始めるかもしれませんね。

使われ方は通常の Makefile の様に使うのも良いですが、メタビルドシステムと連携して使うと便利で、例えば gyp のジェネレータとして使う方法もある様です。
NinjaBuild - chromium - Using the Ninja build system - An open-source project to help move the web forward. - Google Project Hosting

Help me to solve this error [44/11153] CC obj\third_party\lzma_sdk\lzma_sdk.7zAlloc.obj FAILED: ninj...

https://code.google.com/p/chromium/wiki/NinjaBuild

SQL で CSV のデータを抽出出来る textql

$
0
0
CSV ファイルを扱っている時に、最大値最小値と得たり合計を得たりするのにいちいち Excel を起動するのはとても面倒ですし、スクリプトを書くのも面倒。
そんな場合は textql を使うと便利です。
dinedal/textql - GitHub

Execute SQL against structured text like CSV or TSV

https://github.com/dinedal/textql
golang で書かれています。ビルドすると依存性の無い実行モジュールが生成されます。使い方はリンク先の動画gifを参照下さい。
簡単にどんな事が出来るかというと
$ cat ~/sample_data.csv | textql -header -sql "select sum(cast(value as integer)) from tbl"
18
こんな事が出来るツールです。中身は実は sqlite3 を使っています。 ただ go-sqlite3は amalgamation code を含んでいるので実行モジュールに依存物がありません。 textql-dependency
なので Windows なら exe 一つを USB メモリなんかに持っていればいざ困った時に使えるかもしれませんね。

C言語で文字列を自動伸張してくれるライブラリ「sds」

$
0
0
C言語の文字列伸張は慣れないとコストの掛かるコーディングになりがちです。
またそういった文字列ライブラリというのは、直接 puts や printf に放り込めないという難点があります。
しかし sds というライブラリは異なります。
antirez/sds - GitHub

Simple Dynamic Strings SDS is a string library for C designed to augment the limited libc ...

https://github.com/antirez/sds
通常、C言語向け文字列ライブラリというのは独自の構造体ポインタを返します。そうする事で、文字列ポインタ以外の情報を詰め込んで処理する事が出来ます。しかしその反面、構造体ポインタをそのまま puts や printf に放り込めず、何かしらのアクセサを用意する必要がありました。
printf("%s\n", string->buf);
しかし sds の場合はそれが出来ます。
printf("%s\n", sds_string);
sds *tokens;
int count, j;

sds line = sdsnew("Hello World!");
tokens = sdssplitlen(line,sdslen(line)," ",1,&count);

for (j = 0; j < count; j++)
    printf("%s\n", tokens[j]);
sdsfreesplitres(tokens,count);

output> Hello
output> World!
トリックとしては、sds で生成された文字列は必ず sds 構造体のメンバに格納されている前提ですので、sds 文字列ポインタは構造体の先頭ポインタからのオフセット分シフトした所に位置します。
つまり sds 文字列ポインタからヘッダのバイト数分アドレスを戻せば、補足情報を得られるという仕組みです。
それの証拠に sdslen は以下の様なコードになっています。
static inline size_t sdslen(const sds s) {
    struct sdshdr *sh = (void*)(s-sizeof *sh);
    return sh->len;
}
個人的にはC言語での文字列操作は慣れてしまっているのでスルーで良いかなと思いましたが、仕組みは面白いと思いました。

ファイル名の一括置換なら massren がめちゃめちゃ便利

$
0
0
大量にあるファイルのファイル名を一括で変更する場合、どうしても GUI での操作であったりマッチパターンを書くのが面倒だったりしましたが、massren を使えば誰でも簡単にファイル名の一括置換が出来る様になります。
laurent22/massren - GitHub

massren - Easily rename multiple files using your text editor

https://github.com/laurent22/massren
お気に入りのテキストエディタを使って、好きな様にファイル名を変更出来ます。サポートしているOSは Windows, Linux, OSX です。中身は golang で書かれています。
それぞれバイナリが用意されているので自分でビルドする必要はありません。Linux と OSX の人はリンク先にある手順を、Windows の人は専用ページからダウンロード出来ます。
起動する前にエディタを設定しましょう。
$ massren --config editor vim
そしてファイル名を一括変更したい場所に移動して massren を起動します。エディタ内にファイルの一覧が書かれているので、vim やお気に入りのテキストエディタで好きな様に編集します。
最後に書き込んでエディタを終了すればファイル名が変更されています。
massren
Windows であれば
$ massren /n
OSX や Linux では
$ massren -n
で dry-run モードで起動出来ます。また引数にディレクトリやワイルドカードなファイル名も指定出来ます。
めちゃめちゃ便利ですね。

ぼくがかんがえたさいきょうの rebuild.fm クライアント

$
0
0
最強というか、正直懐かしい感じではありますが...
まず mpd と mpc と podget を入れましょう。
$ sudo apt-get install mpd mpc podget
そして ~/.podget/serverlistに rebuild.fm を足しましょう。
http://feeds.rebuild.fm/rebuildfm Rebuild
crontab で自動起動します。
0 0 * * * /usr/bin/podget -s
Ubuntu の場合 /usr/lib/mpdにファイルを置く事になるので
$ sudo usermod -aG audio `whoami`
として書き込み権限を得た後
$ sudo ln -s ~/POD/Rebuild /usr/lib/mpd/Rebuild
シンボリックリンクを張りましょう。
次に mpd のインデックスを自動更新にしましょう(コメントを外す)。
auto_update "yes"
これだけで Linux や OSX 環境では聞ける様になったので Music Player Daemon プロトコル対応のプレーヤさえ探してくれば再生出来ますし、mpd なので何処からでも誰でも(パスワード設定可能)音楽を鳴らせます。mpd はサーバで音を鳴らす代物なので会社のBGMサーバなんかにいいんじゃないかなーとか思います。
また audio_output を httpd にすればストリーミング配信出来るので別の端末でも再生出来ます。
audio_output {
    type        "httpd"
    name        "My HTTP Stream"
    encoder     "vorbis"        # optional, vorbis or lame
    port        "8000"
    #quality        "5.0"           # do not define if bitrate is defined
    bitrate     "128"           # do not define if quality is defined
    format      "44100:16:1"
}
こうしておけば http://localhost:8000/mpd.ogg でストリーミング再生出来ますし、bind_to_addressをネットワークアドレスに設定して MPDroid入れれば、いつでもどこでも Rebuild.fm が聞けますね。この環境、一度作っておくと上記の mpd のフォルダに適当に mp3 ファイルを放り込んでおけば自宅を出ても MPDroid で聞ける様になります。

Rebuild.fm 関係ないですねそうですね。


ちなみに...

golang で rebuild.fm クライアント書いてますんで、使いたい人はどうぞ。
mattn/rebuildfm - GitHub
https://github.com/mattn/rebuildfm
あと vim 版もあります。
mattn/ctrlp-rebuildfm - GitHub
https://github.com/mattn/ctrlp-rebuildfm

golang の mime/multipart で独自の Content-Type を付ける。

$
0
0
Twitter / ymmt2005: むう、mime/multipart の ...

むう、mime/multipart の CreateFormFile の Content-Type は application/octet-stream 固定になっている。泣ける。。#golang https://code.google.com/p/go/source/browse/src/pkg/mime/multipart/writer.go#128

https://twitter.com/ymmt2005/status/431143170659717120
ファイルから multipart.CreateFormFileを呼ぶと io.Writer が返ります。この writer は隠ぺいされているのでパートのヘッダを書き換える事は出来ません。
この場合は multipart.CreatePartを使います。
package main

import (
    "bytes"
    "io"
    "log"
    "mime/multipart"
    "net/textproto"
    "os"
)

func main() {
    var b bytes.Buffer
    w := multipart.NewWriter(&b)
    part := make(textproto.MIMEHeader)
    part.Set("Content-Type""application/vnd.ms-excel")
    part.Set("Content-Disposition"`form-data; name="file"; filename="Foo.xlsx"`)
    pw, err := w.CreatePart(part)
    if err != nil {
        log.Fatal(err)
    }
    f, err := os.Open("Foo.xlsx")
    if err != nil {
        log.Fatal(err)
    }
    io.Copy(pw, f)
    w.Close()

    b.WriteTo(os.Stdout)
}

C言語で可変個引数を型拘束したい

$
0
0
C言語で可変子引数扱う場合は va_start/va_arg/va_end を使うのだけど...
#include <stdio.h>
#include <stdarg.h>

void
foo(int n, ...) {
  va_list list;
  int i;
  va_start(list, n);
  for(i = 0; i < n; i++)
    puts(va_arg(list, char*));
  va_end(list);
}

int
main(int argc, char* argv[]) {
  foo(3"foo""bar""baz");  
  return 0;
}
型が拘束出来ない。なので
foo(31"bar""baz");  
こんな呼び出し方が出来てしまうし、コンパイルエラーや警告も出ない。実行時にクラッシュする。
なんか出来ないかなーと思ってマクロの海へ...
#include <stdio.h>
#include <stdarg.h>

void
foo(int n, ...) {
  va_list list;
  int i;
  va_start(list, n);
  for(i = 0; i < n; i++)
    puts(va_arg(list, char*));
  va_end(list);
}

#define bar(...) foo((sizeof((char*[]){__VA_ARGS__})/sizeof(char*)), __VA_ARGS__)

int
main(int argc, char* argv[]) {
  bar("foo""bar""baz");
  return 0;
}
これだと引数の個数指定も要らなくなる。エラーにはならないものの、警告は出るので少しはメリットあるかも。
vaarg.c: In function 'main':
vaarg.c:18:3: warning: initialization makes pointer from integer without a cast [enabled by default]
vaarg.c:18:3: warning: (near initialization for '(anonymous)[0]') [enabled by default]

bundle exec がウザい

$
0
0
ruby のアプリを動かす時にいちいち bundle execって書くのがダルい。書きたくない。でもシステムに入ってたり違うバージョンの物が動いて変な動作をされても困る。
どうにかしてこのダルさを解消できないかと考えてみた。

まず rbenv を使ってるなら gem でインストールされるコマンドは必ずシェルのラッパとして生成され、そこから本物が起動する様になっている。例えば rails であれば以下の様なシェルになっている。
#!/usr/bin/env bash
set -e
[ -n "$RBENV_DEBUG" ] && set -x

program="${0##*/}"
if [ "$program" = "ruby" ]then
  for arg; do
    case "$arg" in
    -e* | -- ) break ;;
    */* )
      if [ -f "$arg" ]then
        export RBENV_DIR="${arg%/*}"
        break
      fi
      ;;
    esac
  done
fi

export RBENV_ROOT="/home/mattn/.rbenv"
exec "/home/mattn/.rbenv/libexec/rbenv" exec "$program" "$@"
おっと、運良く /usr/bin/envを使ってくれている。つまりはパスを書き換えれば rails とタイプしたコマンドを自前のコマンドに置き換えられるという事だ。
って事で direnvを入れよう。
direnv - unclutter your .profile

Usage Use direnv edit . to open an ".envrc" in your 1EDITOR. This script is going to be executed onc...

http://direnv.net/
$ go get github.com/zimbatm/direnv
bash をインタラクティブシェルに使っているなら以下を .bashrcに追加する。
eval "$(direnv hook bash)"
これでこのディレクトリ特有のフックが実行出来る。次に rails や middleman 等を起動しているディレクトリに .envrcというファイルを作ろう。
中身はパスを書き換えるだけ。
export PATH=$PWD/.bin:$PATH
シェルを起動し直すか source ~/.bashrcした後でこのディレクトリに移動すると
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
と怒られる。すかさず
$ direnv allow
を実行しよう。さて、後は .binというディレクトリを作り、その中に bashというファイルを作る。勘のいい方であればそろそろ気付いたはず。
#!/bin/bash

PATH=`echo $PATH sed 's/^[^:]*://g'` bundle exec "$@"
追加したパスを元に戻して bundle exec "$@"しています。
これでいちいち bundle exec middlemanとかしなくても middlemanとするだけで同じコマンドが実行出来る様になります。

さようなら、bundle exec、いい思い出をありがとう。

ちなみに shebang が bash じゃなくて perl な物を起動しようとしているなら同様に .bin/perlを書いてしまえば、carton execにも対応出来るかもしれませんね。
(だらだら書いてますが bundle install --binstubsしてそこにパス通すのでいいです)

WordPress のトラックバック機能が危ない

$
0
0
トラックバック/ピンバック機能は XMLRPC というプロトコルが使われているんだけど、WordPress のトラックバック/ピンバック実装に問題があるらしく DDoS となる危険性があるらしい。
詳しくは以下のサイトを見て貰いたい。
More Than 162,000 WordPress Sites Used for Distributed Denial of Service Attack | Sucuri Blog

Distributed Denial of Service (DDOS) attacks are becoming a common trend on our blog lately, and tha...

http://blog.sucuri.net/2014/03/more-than-162000-wordpress-sites-used-for-distributed-denial-of-service-attack.html
「設定」→「ディスカッション」→「他のブログからの通知 (ピンバック・トラックバック) を受け付ける」というチェックボックスでオフには出来るけど...
トラックバック/ピンバック無効
実はこれだけではダメで既存でトラックバック/ピンバックを受けた事がある記事を全て無効にして回らないといけない。

プラグインの新規追加から「disable-xml-rpc」で検索して出てくる「Disable XML-RPC」を入れておくと、以下の様にトラックバック/ピンバック機能を無効にするプラグインフィルタが登録される。
add_filter('xmlrpc_enabled','__return_false');
WordPress › Disable XML-RPC « WordPress Plugins

Pretty simply, this plugin disables the XML-RPC API on a WordPress site running 3.5 or above. Beginn...

http://wordpress.org/plugins/disable-xml-rpc/
WordPress 本体に対処が入るまではこの設定をしておいた方がいい。

pure mruby な JSON パーサ書いた。

$
0
0
良く分からないけどニーズがある様なので書いた。
1~2時間程度で書けると思ったのに予想以上に ruby 戦闘能力が無くて泣いた。
mattn/mruby-pjson - GitHub
https://github.com/mattn/mruby-pjson
今の所 parse しかないので dump も付けたい。
あとまだまだ色んな所で甘いので直さないといけない。

Vim のソースから「#ifdef FEAT_VISUAL」が消えた。

$
0
0
Patch 7.4.212
https://groups.google.com/forum/#!topic/vim_dev/0nx0RLbJhmk
Patch 7.4.212 (after 7.4.200)
Problem: Now that the +visual feature is always enabled the #ifdefs for it
are not useful.
Solution: Remove the checks for FEAT_VISUAL.
最新のソースで TINY FEATURE でビルドしても Visual モードは使えるので、一見なんの変哲もないパッチだが、意外と大きなパッチだったと思ってる。
いままで Vim はどんな事があろうとも #ifdef で切り抜けて来たし、obsolute だから動かない環境は無視しようとといった事を自らは言わない方針だったと記憶してる。
先日、Tiny ビルドでも Visual 選択有効にしようという持ちかけに対して誰も意見しなかった。
About Patch 7.4.200
https://groups.google.com/d/msg/vim_dev/IVsjvq-KUg4/rshKSw-9-_QJ
時代の流れとういかなんというか、Vim もそろそろ古い物を保守する為に新しい何かを犠牲にしなければいけない状態になって来ている。

もう Vim のソースでは Visual モードの無い vi はコンパイル出来ないのだ。

Emoji の入力を簡単にする Vim plugin 書いた。

$
0
0
README.md なんかは Vim で編集する事が多いんだけど、github の絵文字(エモジ ダイジ ゼッタイ...)を入力する際に、「アイコン足したいけどブラウザ起動すんのかったるいな」って事あると思います。
そんな時には emoji-vim をお使い下さい。
mattn/emoji-vim - GitHub

Emoji selector

https://github.com/mattn/emoji-vim
:Emojiで起動します。初回だけダウンロードして解凍(Windows の場合は png から bmp への変換も行います)するので、ちょっと時間が掛かります。起動すると以下の様な画面になります。
emoji-vim
リターンキーを押すと、クリップボードにマーク(:+1:)が格納されます。

どうぞお使い下さい。
Windows の場合は .NET Framework 4.5 が必要になります。 自前で png ファイルをダウンロードして格納頂ければ必要ありません。

簡単に LGTM 出来る Vim plugin 書いた。

$
0
0
LGTM
README.md なんかは Vim で編集する事が多いんだけど、github の LGTM(Looks Good To Me)を入力する際に、「適当な画像欲しいけどブラウザ起動すんのかったるいな」って事あると思います。 そんな時には lgtm-vim をお使い下さい。
mattn/lgtm-vim - GitHub
:LGTM
で LGTM.in から適当な画像を引っ張ってきます。
また <leader>lgtmでも動きます。
LGTM.in
http://lgtm.in

どうぞお使い下さい。
動作には webapi-vim が必要です。
Viewing all 121 articles
Browse latest View live