ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

Slack の投稿を画面上に流そう!

みなさんこんにちは!サーバーサイドエンジニアの柿本です。

Zoom などの WEB 会議で自分の画面を共有している時、参加者の反応がよくわからなかったりチャットの投稿に気がつかないという経験をしたことはありませんか?

特に私はプレゼンの類が苦手(というか緊張する)なので、チャットのアイコンにバッジがついても全く気がつかないのです。

ならいっそのこと、動画共有サイトのように、参加者のコメントが画面上に流れるようにすれば流石に気づくでしょ!ということで、チャットの投稿が画面に流れるようにしました。

TL;DR

Comment Party という Slack app として実装しました!

  1. Comment Party の Chrome 拡張をダウンロード
  2. 拡張機能管理画面( chrome://extensions )で「デベロッパーモード」を ON にして「パッケージ化されていない・・・」から読み込み
  3. Chrome を再起動
  4. こちらから「Add to Slack」して Comment Party を Slack にインストール
  5. Comment Party app を追加した Slack チャネルで /party !!
  6. 発行される PARTY ID を Chrome 拡張のポップアップにペーストして【START】!!

構想

Zoom の共有画面にチャットのコメントをそのまま流せると素敵な感じがしますが、専用の SDK が必要になりそうです。また、Google Meet を使うこともあるのでちょっと汎用性が足りません。

Unifa では Slack を使っていて、ルクミーの推奨環境である Chrome を使っている人が多いので、Slack への投稿メッセージが Chrome の画面に流れるようにしました。

実際に作ってみたらパーティー感があって面白かったので Comment Party と名付けることにしました!! ​🥳

最終形態

Comment Party Demo
Comment Party デモ

技術スタック

  • 言語/実行環境: Node.js
  • フレームワーク: Bolt - Slack 社製のアプリフレームワーク
  • データベース: Firestore
  • インフラ: Google App Engine
  • CI/CD: GitHub Actions
  • WebSocket Platform: Pusher

全体図

Comment Party diagram
Comment Party 全体図

実装のポイント

Comment Party の Slack app 本体は以前のエントリーでご紹介した Slack じゃんけんをほぼそのまま流用しました。

tech.unifa-e.com

Pusher の Encrypted Channels

メッセージを Slack app から Chrome 拡張に送るために、WebSocket のプラットフォームを API 提供している Pusher を利用しました。

pusher.com

Slack への投稿内容が Chrome 拡張に表示されるまでの間、TLS 経由とはいえなるべくセキュアにするために、メッセージを暗号化する機能を備えた Encrypted Channels を使うことにしました。

cron.yaml で GAE にジョブ登録

パーティーの開催時間は 40 分間にしてあります。終了の約 10 分前に主催者に知らせるため、 cron でジョブを実行することにしました。

GAE では cron.yaml にジョブ内容を記述して deploy すれば良いのですが、 google-github-actions/deploy-appengine を使って GitHub の Actions で Deploy するには deliverablescron.yaml を追加する必要があります。

// .github/workflows/gae-deploy.yml

      - name: Deploy to App Engine
        id: deploy
        uses: google-github-actions/deploy-appengine@v0.2.0
        with:
          deliverables: app.yaml cron.yaml  // <-- 追加
        ...

また、同じ GCP プロジェクトの cron からの実行であることを検証するために、 request の最初に HTTP ヘッダーの validation を追加しました。

// src/requests/close_notification.ts

  app.receiver.app.get(`/close_notification`, async (req, res) => {
    if (process.env.NODE_ENV === 'production') {
      const fromGae = req.header('X-Appengine-Cron') === 'true' &&
        req.header('X-Forwarded-For').split(',')[0].trim() === '0.1.0.2';
      if (!fromGae) {
        res.status(401).send();
        return;
      }
    }
    ...

Google スライドのプレゼンモードに対応

Google スライドのプレゼンモードがどのように動いているのか考えたことはあまりなかったのですが、よくよく調べたら iframe を使っていることがわかりました。

なので、iframe の子エレメントにメッセージ表示のエレメントを append してあげれば簡単に表示できました。

最後に

Slack app から Chrome 拡張へメッセージを送る仕組みを Pusher を使ったことで、メッセージ送受信の実装は非常に簡単でした。

WebSocket サーバーを自分で準備するとなるとその運用だけで手一杯になってしまうので、Pusher のようなサービスは非常に助かりますね!

リアルタイム通信において WebSocket 技術は非常に有用なので、色々な活用方法を考えてみたいと思います。

ユニファでは保育をハックするエンジニアを募集中です!

unifa-e.com