一週間前にめっちゃやる気出たので作ってました。
できること
シンプルにGaroonとGoogle Calendarでの予定の追加、更新、削除に関する同期が可能です。
注意点
メンバーは同期されない
garoonとgoogle calendarではメンバーが異なるので、基本的に1人用の設計となっています。
e.g. google calendarで予定を作っても自分しかいない等
削除と更新には制約がある
google calendarではundoができたりするので、影響範囲を小さくするため、自分以外の他のメンバーが入っている予定に対しては、デフォルトでGaroon側の予定を消さない and 更新できない仕様になっています。
もし制約を外したい場合は、.envのSAFETYをfalseするとすべてのイベントに対してこの制約をなくします。
Garoonからの状態は反映に時間がかかる
中央のgaoogleに対しては、以下のように接続します。
- google calendarはwebhook
- garoonはcrontabでAPIを叩く
つまり、google calendarから予定を変更した場合はリアルタイムに反映されますが、garoonはcrontabによりキックされAPIを叩くため、指定した時間にしかgoogle calendarに反映されません。
モチベーション
自分の予定を入れるのに、2つのカレンダーに登録するのが面倒くさくなってきたのが主な理由です。(エンジニアっぽい。。)
以前、サイボウズの方で出ているJavaの試したのですが証明書周りで使えなかったと、
サイボウズの方はgaroonからgoogle calendarの一方向なので、google calendarから予定の登録できないのは辛いなって思ったので書きました。
自分も最初のコミット時には、garoon -> google calenadarの目的でしたが。。。
github.com
アーキテクチャ
構成
- app
- garoonをcrontabで動かし、google calendarのwebhookをwatchしています
- mysql
- metaデータと共有フォーマットな予定データを格納しています
- batch
- google calendarの
Events:watch実行とチャンネル作成サーバー
- google calendarの
上記をdocker-compose内に入れて動かしています。
+-----------------+ +-----------------+
| | | |
| Garoon | | Google Calendar |
| | | |
+----+------------+ +-----+-----+-----+
^ | ^
| | |
fetch | webhook | | post
by crontab | +---------------------+ | for updating a channel
| | |
| | |
+----+---v--+ +-----+-----+
| | | |
| app | | batch |
| | | |
| | | |
+-+--+------+ +-----+-----+
| ^ |
| | get | insert
insert | | events +-----------+ | the latest channel information
nextSyncToken and events | | | | |
| +---------+ mysql | |
| | <---------+
+----------->+ |
+-----------+
Google Calendar APIの流れ
Push Notifications | Calendar API | Google Developers
大きく分けて、2つ仕組みが必要です。
定期的にwebhookを動かすようにするためにgoogle calendar apiを叩くアプリ
webhookのチャンネルには、寿命がありそれが切れると送られなくなります。
なので、チャンネルの寿命が無くなる前に、別チャンネルを発行し、切り替える必要があります。
Events::watchにユニークなチャンネルのIDを付け、POSTします。Events::watch- 使わなくなったチャンネルは
Channels::stopを叩き、止めます。Channels::stop
上記の処理を定期的に実行する必要があります。
が、自分の場合、x-goog-channel-id と x-goog-resource-id の値を付けても404となってしまいstopできないので、放置しています。。。
webhookを監視するためのアプリ
- google calendarに登録した、コールバックのURLが叩かれる
- headerに入っている
x-goog-resource-stateにはその2つの種類があり、syncとexistがある - 前回保存したnextSyncTokenを付け、
Events::listを叩く - nextSyncTokenを保存する
2の種類には、以下の種類があります。
sync: チャンネルが作られたexist: 予定が操作(作成、更新、削除)された
また、Events::listというAPIは、普通に叩いてもすべてのデータが返ってくるので、前回との差分を出すには、offsetを指定する必要があります。
このAPIを叩くと、headerにnextSyncTokenというoffsetの値が入っているので、次回叩くときにこの値を付与します。
garoogle/google-calendar.js at master · hiroppy/garoogle · GitHub
所感
Google CalandarとGaroonみたいな2区間のプロパティを合わせるのは大変だなって思ったのと、webhookのデバッグ大変すぎる〜〜。
もし、google calendarとgaroonをつなぎたい人は使ってみてください:)