2013/02/21


一般的なGo言語プログラマならば、HTTP Status code はすべて暗記していると聞きました。

しかし、僕は初心者なので、なかなか覚えきれていないので、IRC から HTTP のステータスコードをさがすのに便利なツールを用意しました。
go-httpstatusbot です。インストール方法は go get . として ./httpstatusbot と実行して下さい。 package main

import (
    "fmt"
    irc "github.com/fluffle/goirc/client"
    "os"
    "regexp"
)

var pattern = regexp.MustCompile(`^\s*(HTTP|http) ([0-9]+)\s*$`)
var httpstatus = map[string]string {
  "100""Continue",
  "101""Switching Protocols",
  "102""Processing",
  "200""OK",
  "201""Created",
  "202""Accepted",
  "203""Non-Authoritative Information",
  "204""No Content",
  "205""Reset Content",
  "206""Partial Content",
  "207""Multi-Status",
  "208""Already Reported",
  "300""Multiple Choices",
  "301""Moved Permanently",
  "302""Found",
  "303""See Other",
  "304""Not Modified",
  "305""Use Proxy",
  "307""Temporary Redirect",
  "400""Bad Request",
  "401""Unauthorized",
  "402""Payment Required",
  "403""Forbidden",
  "404""Not Found",
  "405""Method Not Allowed",
  "406""Not Acceptable",
  "407""Proxy Authentication Required",
  "408""Request Timeout",
  "409""Conflict",
  "410""Gone",
  "411""Length Required",
  "412""Precondition Failed",
  "413""Request Entity Too Large",
  "414""Request-URI Too Large",
  "415""Unsupported Media Type",
  "416""Request Range Not Satisfiable",
  "417""Expectation Failed",
  "418""I'm a teapot",
  "422""Unprocessable Entity",
  "423""Locked",
  "424""Failed Dependency",
  "425""No code",
  "426""Upgrade Required",
  "428""Precondition Required",
  "429""Too Many Requests",
  "431""Request Header Fields Too Large",
  "449""Retry with",
  "500""Internal Server Error",
  "501""Not Implemented",
  "502""Bad Gateway",
  "503""Service Unavailable",
  "504""Gateway Timeout",
  "505""HTTP Version Not Supported",
  "506""Variant Also Negotiates",
  "507""Insufficient Storage",
  "509""Bandwidth Limit Exceeded",
  "510""Not Extended",
  "511""Network Authentication Required",
}

func main() {
    c := irc.SimpleClient("httpstatusbot""httpstatusbot")
    c.EnableStateTracking()

    c.AddHandler("connected"func(conn *irc.Conn, line *irc.Line) {
        for _, room := range os.Args[1:] {
            c.Join("#" + room)
        }
    })

    quit := make(chan bool)
    c.AddHandler("disconnected"func(conn *irc.Conn, line *irc.Line) {
        quit <- true
    })

    c.AddHandler("privmsg"func(conn *irc.Conn, line *irc.Line) {
        if pattern.MatchString(line.Args[1]) {
            m := pattern.FindStringSubmatch(line.Args[1])
            if status, ok := httpstatus[m[2]]; ok {
                c.Notice(line.Args[0], status)
            }
        }
    })

    for {
        if err := c.Connect("irc.freenode.net:6667"); err != nil {
            fmt.Printf("Connection error: %s\n", err)
            return
        }
        <-quit
    }
}
使い方は... もういいですね。わかります。 今日の参考資料
http://blog.64p.org/entry/2013/02/21/121830
http://mattn.kaoriya.net/software/vim/20130221123856.htm
Posted at by



2012/12/13


Go Playground で time パッケージが有効になった。
Go Playground

The Go Playground is a web service that runs on golang.org 's servers. The serv...

https://play.golang.org
公式発表
Time - Google Groups
https://groups.google.com/d/topic/golang-nuts/JBsCrDEVyVE/discussion
\x0c というコードを fmt.Print() で出力するとクリアされ、fmt.Print()fmt.Println() を使って文字列を出力、time.Sleep を使ってアニメーション表示が出来る様になります。
こういうの出来たら、これを試さない訳にはいかない!!!
Go Playground
http://play.golang.org/p/NOycgN2i6b
goplayground
皆さんも面白いの作ってみて下さい。
Posted at by



2012/12/04


以前、こんな記事を書いた。
Big Sky :: 日本語grepが出来るjvgrepというのを作った。
http://mattn.kaoriya.net/software/lang/go/20110819203649.htm
実は jvgrep を作った当初、処理がかなり遅かった。まぁ複数のエンコーディングを試すからしょうがないよね程度に思ってたけど、どうにか速くならないかと思い、処理の並行化を行ってパフォーマンスを向上させた。この記事はその時にやった改善策。

jvgrep は -R オプションや **/* で再帰検索する機能が付いているんだけど、これを行う場合
  • find
  • grep
という処理が走る事になる。 しかしながら結果の順番を守ろうと考えた場合、find と grep を安直に同時に走らせる訳にはいかなくなる。走らせると結果が交錯してしまうからだ。
こういうのを行う場合、C言語だとFIFOキューとスレッドを作り、find 側が push、grep 側が pop を行う仕組みを作る。
しかしながらメモリの増加を管理したり、grep 側が空きになった時に待機する処理ってのを考えると、C言語だと結構めんどくさかったりする。

Go言語はこのあたりが非常に簡単に実装出来る様になっている。

まず find 部と grep 部の処理を分割し、grep 部を FIFO キューに対して連続で呼び出せる様にする。 func GoGrep(ch chan *GrepArg, done chan int) {
    for {
        arg := <-ch
        if arg == nil {
            break
        }
        Grep(arg)
    }
    done <- 1
}
Grep が本体だが今回の話の本質ではないので省略。引数の ch に Grep が使う引数が飛び込んで来る。全ての grep 対象が完了するか途中終了する場合には find 側から nil を渡すというお約束にした。
メインコントローラ側で、この FIFO となるチャネルを作る。 ch := make(chan *GrepArg)
done := make(chan int)
なぜ二つチャネルを作っているかというと、find 側が先に終了してしまった場合にプログラムが終了しない様、待機する為で、上記の GoGrep の最後に 1 を渡している。 チャネルを作ったら GoGrep をバックグラウンドで起動する。 go GoGrep(ch, done)
Go言語は関数呼び出しに go を付けるだけで非同期に実行してくれる。
次に find 部。Go言語の filepath パッケージにはファイルが見つかる度にコールバック関数を呼び出してくれる Walk がある。
filepath.Walk(root, func(path string, info os.FileInfo, err errorerror {
    if info == nil {
        return err
    }

    // 以下 path に対する処理を行う。
    path = filepath.ToSlash(path)

    // 検索対象外のパスにマッチする場合
    if ere != nil && ere.MatchString(path) {
        // ディレクトリならば SkipDir を返して他のフォルダに移る
        if info.IsDir() {
            return filepath.SkipDir
        }
        // ファイルならば以下の処理は行わない
        return nil
    }

    // ... 省略 ...

    // 検索対象のファイルならば
    if fre.MatchString(path) {
        // GoGrep が待っているチャネルにパラメータを渡す
        ch <- &GrepArg{pattern, path, /* ... 省略 ... */}
    }
})
検索対象のファイルが見つかった場合、先ほど作成した ch に Grep 引数を渡している。
find 側は全てのファイルを検索し終えたら grep 側に処理の終了を伝える。 ch <- nil
そして grep の終了(done)を待つ。 <-done
図解すると
jvgrep
こんなイメージになる。find もフォルダを再帰的に検索すると結構重くなるので各処理を並行実行させる事でかなりのパフォーマンス向上が得られた。

最初から find 部と grep 部が関数分けされていれば、もっと簡単に並行処理の実装が出来た事になる。
Posted at by