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