手元のPCで動かせる slackbot を作って遊ぶ (3)

前回:手元のPCで動かせる slackbot を作って遊ぶ (2)

前回用意した bot だと,websocket からメッセージが来るまで待機しちゃうので, 3時になったら「おやつだよー」と知らせてくれる機能を入れようとすると,どうもしっくりきません.

websocket からのメッセージも,時間をチェックするタイミングも,golang らしく channel で 制御してやることでそれとなくまとまりがつきます.

github.com

slack のイベントループをこんな感じでまとめました. ミソは,GetMessage() で websocket を待つ部分を goroutine に切り出して,websocket から来るメッセージを channel で受け取るという点です.

func Run(bot *otemoto.Bot, notify <-chan struct{}, done chan<- struct{}) {
    msgch := make(chan otemoto.Message, 1)
    errch := make(chan error, 1)
    go func() {
        for {
            msg, err := bot.GetMessage()
            if err != nil {
                errch <- err
            }
            msgch <- msg  // メッセージをチャンネルで送る
        }
    }()
        scheduleTimer := time.NewTicker(interval)
        defer scheduleTimer.Stop()
loop:
    for {
        select {
        case <-notify:
            log.Println("slackbot, receive exit message...")
            break loop
        case err := <-errch:
            log.Printf("receive error, %v", err)
        case msg := <-msgch:                                 // メッセージが来たら処理する
            if bot.ID == msg.MentionID() {             // ここに必要な処理を goroutine にして書けばいい
                go bot.Tokenize(msg)
            }
        case <-scheduleTimer.C:                            // ここは一定間隔でスケジュールをチェックして
            go bot.CheckSchedule()                      // お知らせしてくれる処理を書く
        }
    }
    done <- struct{}{}
}

こうすることで,メッセージの処理と,他の処理をそれとなくまとめて書くことが出来ます.

main の方で,

 sys := make(chan os.Signal, 1)
    signal.Notify(sys, syscall.SIGINT)
    exit := make(chan struct{}, 1)
    done := make(chan struct{}, 1)

    go Run(bot, exit, done) // slack event loop
loop:
    for {
        select {
        case <-sys:
            log.Println("received ^C ...")
            exit <- struct{}{}
            break loop
        }
    }
    <-done
    log.Println("done")

こんな感じに書いておけば,^C が押されたときに,slack の処理の方に通知がいって,slack の処理から停止の応答があったときにプログラムを終了することが出来ます.

他にも工夫すれば deploy を bot からおこなったり,勤怠を bot からおこなったり いろいろ出来ると思うので,改造したりして遊んでください.