2013/12/25

Recent entries from same category

  1. Go 言語プログラミングエッセンスという本を書きました。
  2. errors.Join が入った。
  3. unsafe.StringData、unsafe.String、unsafe.SliceData が入った。
  4. Re: Go言語で画像ファイルか確認してみる
  5. net/url に JoinPath が入った。

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)
    }
}
やばい。簡単すぎる。
Posted at by | Edit