Go
golang
docker
bot
dcoker-compose

ノンプログラマの友達と遊べるDiscord BotをGoで作ってみた

最近話題のDiscord Botを作ってみたので、ノンプログラマの友達と遊べるDiscord Botという名目で公開しました。
github.com/aimof/discatにソースをMITライセンスで公開中です。

デモ

Screenshot from 2018-07-08 18-40-54.png

一日の始まりは挨拶から!

というわけで、文書に予め決めておいたランダム返答を返します。

機能

  • 人口無能的に決められた単語をトリガーに決められた返答を返す機能。
  • 発言数に応じてレベルが上がっていく機能(下)

Screenshot from 2018-07-08 18-39-35.png

レベルが上がったり下がったりしているのはdockerのストレージ永続化に失敗しているからです。

どの辺がノンプログラマーと一緒に楽しめるの?

なんとこのボット、セリフをGoogle SpreadSheetで編集できるようにしました。(自動デプロイはまだないので手動でcsvを移植する必要があります)

設定ファイルはこんな感じ

Screenshot from 2018-07-08 18-48-48.png

ライブラリ

ライブラリとしても利用でき、シンプルに上の機能だけ返すようになっています。

技術的ないろいろ

技術面で考えたことを書いていきます。あんまり難しいことはしていないので、書くことは多くないかも

ライブラリのメイン

discat.go
package discat

type Discat struct {
    speaker speaker
    level   level
}

func Init(dict [][]string, expMap map[string]int) Discat {
    return Discat{
        speaker: newSpeaker(dict),
        level:   level{exp: expMap},
    }
}

func (d Discat) Speak(input string) string {
    return d.speaker.speak(input)
}

func (d Discat) GainExp(name string, exp int) {
    d.level.gainExp(name, exp)
}

func (d Discat) ShowLevel(name string) (exp, level, rest int) {
    return d.level.showLevel(name)
}

func (d Discat) Output() map[string]int { return d.level.output() }

Goっぽく書くことを意識したらこうなったのですが、これでいいのだろうか…。ライブラリは、ただ文字列をもらって文字列や数字を返すだけのシンプルなものにしました。それ以上の機能はコマンド側で実装

インタラプトを受け取るよくあるアレ

main.go
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
_ = <-ch
err = session.Close()
if err != nil {
    log.Fatalln(err)
}
// 正常終了処理

インタラプトシグナルからセッションを正常に終了させるやつです。

話す部分は愚直に実装

speaker.go
func (s speaker) speak(sentenceIn string) string {
    for key, value := range s.table {
        if strings.Contains(sentenceIn, key) {
            return value[rand.Intn(len(value))]
        }
    }
    return ""
}

入ってきた文章に対し、持っている単語とかぶっている箇所があれば、対応するレスポンスをリターンします。
同じ文言でもセリフが変わって楽しめます。

tableというフィールド名のmapがあるのは気持ち悪いですね…(今気づいた)

docker-composeでボリュームをマウントできない問題

FROM golang:1.10.3-alpine

LABEL maintainer "aimof <aimof.aimof@gmail.com>"

RUN apk update --no-cache && \
    apk add --no-cache git && \
    go get -u github.com/golang/dep/cmd/dep

COPY . /go/src/github.com/aimof/discat/
WORKDIR /go/src/github.com/aimof/discat/cmd/discat/

RUN dep ensure && \
    go build

CMD ./discat
docker-compose.yml
version: "3"
services:
  discat:
    build: .
    volumes:
      - /home/ubuntu/discat/cmd/discat/data:/go/src/github.com/aimof/discat/cmd/discat/data
    logging:
      options:
        max-size: "10m"
        max-file: "5"
volumes:
  data:

リポジトリをubuntuユーザーホーム直下に置く想定で、こんなdocker-compose.ymlを書いたのですが、なぜかボリュームのマウントに失敗。ローカルでは成功したのだが…

まとめ

Discordボット開発楽しいです。プログラムかけない友達もセリフを考えるところなら参加してもらえるので、もしご興味あれば利用してみてください。
なお、まだプロト段階ですので、まだ使いづらいです。ちょっとずつ改善していきます。