活動の様子

slackのメッセージが3ヶ月間で表示されなくなるのを技術で解決する

slackのメッセージが3ヶ月間で表示されなくなるのを技術で解決する

はじめに

こんにちは。NUTMEGの藤崎です。先日NUTMEG内でLT会が行われ、slack無料プランのメッセージが3ヶ月間で表示されなくなるのをweb+slackAPIを利用してwebアプリを作成し解決した話をしました。今回はその話をもう少し具体的に話していきます。

開発背景

slackの無料プランでは、3ヶ月間でメッセージ表示されなくなってしまいます。自分達NUTMEGや学祭実行委員会内では、3ヶ月前のメッセージも遡りたいこともありますが、利用しているslackは無料プランなので見ることができません。私たちNUTMEGや学祭実行委員会では、予算の関係上slackの有料プランを利用することが困難です。 そのため、有料プランを使用せずに、3ヶ月前のslackを遡る方法としてslackAPI + web技術を使い解決できると考え開発を開始しました。

開発人数と開発期間

本プロジェクトは12月から開始し、個人開発で行っていました。 現在は、興味あるメンバーがいて二人で進めています。

構成と選定理由

今回利用した技術、選定理由としては以下のようになります。

SlackBot

Bolt for Python

チャンネルのメッセージの監視してくれるbotと収集するロジックはBolt for Pythonを利用しました。 Bolt for PythonはSlack 連携アプリを作るための公式フレームワークです。BoltはWebAPIを利用して簡単にメッセージなどの情報を取得することが簡単にできます。 今回は簡単に早く開発したいのもあり、普段から使い慣れているPythonで書くことのできるBoltを採用しました。

バックエンド

Golang

バックエンドはGolangを利用しました。また、APIサーバーはEchoを利用しました。EchoはWebアプリケーションフレームワークであり、3分ほどでAPIサーバーを構築しやすく、普段から使い慣れているので採用しました。 DBからデータを取ってきて、可視化するだけを考えるとバックエンドは不必要そうですが、slackbot, バックエンド, フロントエンドの三層にして、監視、ロジック、可視化の責務を分けることで今後の保守が楽になると考え、導入しました。

フロントエンド

Vue

フロントエンドはVue.jsを採用しました。私は普段はバックエンドを基本的に書いているので、フロントエンドはあまり得意ではなかったのですが、Vueはフロント初心者でも扱いやすいということで採用しました。

DB

MongoDB

データベースはMongoDBを採用しました。MongoDBはNoSqlなので、json形式でデータを保存することが可能です。 slack APIを利用して返ってくるresponseは結構複雑なjsonであり、正規化したりするのは大変だと考えました。そこで取得したjsonをそのままDBに入れられるNoSqlを採用することでこの問題を解決しました。

インフラ

NUTMEG Cloud

デプロイ先には、NUTMEGのインフラチームが開発しているNUTMEG Cloudを採用しました。NUTMEG CloudとはNUTMEGで運用しているオンプレミスサーバーのことです。複数のミニPCを用いて製作してあり、NUTMEGのプロダクトは基本的にここにデプロイされます。

NUTMEGクラウドをもっと詳しく →NUTMEG クラウド

構成図と流れ

構成図

イメージに表すと以下のようになります。

流れ

大まかな流れは以下のようになります。

①botがいるチャンネルで誰かがメッセージを投稿する ②botがチャンネルを監視しており、投稿されたメッセージをMongoDBに保存する ③誰かが、本プロダクトにアクセスする。 ④フロントがAPI requestを行う ⑤バックエンドがDBから必要なデータを取り出し、データを整形する ⑥整形されたデータをフロントに返す ⑦フロントによるメッセージの可視化

苦戦した点

Golangにおけるデータの整形

このプロダクトで最も苦戦したところは、MongoDBから取り出したデータから必要なデータだけに整形するところでした。 MongoDBにはslack APIのレスポンスがそのまま入っています。 DBには以下のようなデータが入っています。slack API message.channelsより引用

{
    "token": "one-long-verification-token",
    "team_id": "T061EG9R6",
    "api_app_id": "A0PNCHHK2",
    "event": {
        "type": "message",
        "channel": "C024BE91L",
        "user": "U2147483697",
        "text": "Live long and prospect.",
        "ts": "1355517523.000005",
        "event_ts": "1355517523.000005",
        "channel_type": "channel"
    },
    "type": "event_callback",
    "authed_teams": [
        "T061EG9R6"
    ],
    "event_id": "Ev0PV52K21",
    "event_time": 1355517523
}message.channels

しかし、実際に必要なデータは、eventkey内のvalueだけでした。そのためMongoDBから取り出したデータからeventkey内の要素だけを取り出し、新しく連想配列に入れていこうとしましたが、なかなかうまくいきませんでした。 原因はmongoDB内で保存されているデータがbson形式だからです。そのため取り出して新しい変数に入れたり、連想配列に格納する際にはキャストする必要がありました。

実際に連想配列に格納するメソッドです。

func (u *mongoDBUsecase) FetchData() []map[string]string {
 docs, err := u.repository.AllCollection()
 usersInfoMap, err := u.repository.GetUserInfo()
 channelsInfoMap, err := u.repository.GetChannelInfo()

 usersInfo := usersInfoMap[0]
 channelsInfo := channelsInfoMap[0]
 var data []map[string]string

 for _, v := range docs {
  var m = make(map[string]string)
  eventTs := v["event"].(bson.M)["event_ts"].(string)
  channel := v["event"].(bson.M)["channel"].(string)
  text := v["event"].(bson.M)["text"]
  threadTs := v["event"].(bson.M)["thread_ts"]
  user := v["event"].(bson.M)["user"]

  m["eventTs"] = eventTs

  channelName := channelsInfo[channel]
  m["channelName"] = channelName.(string)
  m["channelId"] = channel

  if threadTs != nil {
   m["threadTs"] = threadTs.(string)
  }

  if text != nil {
   m["text"] = text.(string)
  }

  if user != nil {
   userName := usersInfo[user.(string)]
   m["user"] = userName.(string)
  }

  data = append(data, m)
 }
 if err != nil {
  panic(err)
 }
 return data
}

もしかしたらもう少し上手にする方法があるかもしれません。本プロダクトではここが一番困難だと感じましたが、改めてgolangの型定義などを学び直すことになりとても勉強になりました。

実際のプロダクト

現在はこんな感じになっています。 サイドバーにはNUTMEGにあるチャンネル一覧があり、クリックするとそのチャンネルの今までのメッセージが見れるページに飛びます。(一部プライバシーのため黒塗りしています。)

今後の展望

まだ完成していない点がいくつかあります。

  • スレッド機能の作成
  • ログイン機能
  • HOMEのようなページ

スレッド機能

現在はスレッドにあるメッセージもそのまま並べられているだけです。今後はスレッド機能をつけて、会話の流れを見やすくしたいと考えています。

ログイン機能

ログイン機能がないため、現在誰でもアクセスできる状態です。そのためログイン機能をつけてNUTMEGメンバーだけが見れるようにしていきたいと考えています。

Home画面

メイン機能はほぼできていますが、HOME画面のようなものがないので、簡単でいいので作成していきたいと思います。

優先順としては、HOME→ログイン機能→スレッド機能くらいで考えています。

感想

久しぶりに個人開発をしてみました。最近勉強しているGolangを利用してwebアプリケーションを1から作れたのはいい経験だと思います。またMongoDBやBoltなどの初めて触る技術も多く、とても楽しんで開発できました。また、フロントエンドはほぼ未経験でしたが、先輩に聞きつつ開発を進め、理解度を深めることができました。さらにフロントエンドを触ることで、いつもフロント陣がどのようなことを考えて開発しているのか少しは理解できたのではないかと思っています。 まだ開発段階ではありますが、完成に向けて頑張ります!! また、この記事の技術のところでデタラメをいってたら申し訳ありません。

最後に

最後まで読んでいただき、ありがとうございました。 LT会で利用した資料とgithubのリンクも添付するので、宜しければ、こちらもご覧ください。

nutmeg-slack

LT会で使用した資料