Gaurunを用いたプッシュ通知用サーバー をたててみた

#はじめに
プッシュ通知はFirebaseなどに任せる方も多いかと思いますが、業務で自前でサーバーをたてて構築する機会があったのでまとめておきます。
類似する記事も多いですが、記事が古くgoとgaurunのバージョンが噛み合ってなかったり
証明書の作成に関して、上手くいかないところもあったので、備忘録がわりに記録しておきます

#使い方

http://IPアドレス:設定したポート/push
に対して

```javascript:
{
    "notifications" : [
        {
            "token" : ["xxx"],
            "platform" : 1, //iOSは１、Androidは2
            "message" : "メッセージ１",
            "title": "タイトル１",
            "subtitle": "サブタイトル１",
            "badge" : 1,
            "category": "category1",
            "sound" : "default",
            "content_available" : false,
            "mutable_content" : false,
            "expiry" : 10,
            "extend" : [{ "key": "url", "val": "..." }, { "key": "intent", "val": "..." }]
        },
        {
            "token" : ["xxx"],
            "platform" : 2,
            "message" : "メッセージ２",
            "title": "タイトル２",
            "subtitle": "サブタイトル２",
            "badge" : 1,
            "category": "category1",
            "sound" : "default",
            "content_available" : false,
            "mutable_content" : false,
            "expiry" : 10,
            "extend" : [{ "key": "url", "val": "..." }, { "key": "intent", "val": "..." }]
        },
    ]
}
```

上記の形式のJSONをPOSTすると,token欄に書かれたデバイストークン（後述にて説明）を持つ端末に各オブジェクトの内容でプッシュ通知が送信される
一つの通知オブジェクト（“notifications”:の各要素）の”token”:欄にデバイストークンは配列として複数登録できるので、同じメッセージを
複数の端末に送信することができる。

次にプッシュ通知の送信に最低限必要な証明書とデバイストークンについて解説する。


#必要なもの
プッシュ通知を送るのに必要なものは

- アプリに紐づくプッシュ通知用の証明書と秘密鍵
（開発用と、開発・本番両用の２種類がある。送信用のライブラリによって必要な形式が違う）
- プッシュ通知を送りたい各端末のデバイストークン

である


##１．	証明書と秘密鍵

以下に今回採用したGauranライブラリに必要な証明書のMacOSでの作成手順を簡単に説明する。
１．アプリのAPNsDeveloperPlatformcert.cer
２．cert.cer(key.p12とする)
３．この２つを書類フォルダに入れたと仮定して、ターミナルにて以下のコマンドを入力し、証明書と秘密鍵のpemファイルを作成

```terminal:
$ openssl x509 -in ~/Documents/cert.cer -inform DER -outform PEM -out cert.pem
$ openssl pkcs12 -in ~/Documents/key.p12 -out key.pem -nodes
```
この手順で作成された２つのpemファイルをscpなりrsyncなどででプッシュ通知送信用のサーバーの任意のディレクトリに配置し、後述の設定ファイルにて読み込むことで、プッシュ通知を送信することができる。



##２．	デバイストークン

デバイストークンは各iOSアプリのソースにてAppleにリクエストを送る処理を記述することで取得できる。
(参考 : [Swiftでプッシュ通知を送ろう！](https://qiita.com/natsumo/items/8ffafee05cb7eb69d815) )
取得したデバイストークンを、例えばログイン時にユーザー情報と一緒にサーバー側に送ることで、ユーザーと端末の紐付けをDB等に保存して、任意のタイミングでプッシュ通知を送ることができる。

デバイストークンはアプリと端末の組み合わせに対して一意であり、同じ端末でもアプリが異なれば、プッシュ通知を送るのに必要なデバイストークンは異なるので、たとえばあるユーザーに関連アプリ別に通知を送りたければ、それぞれのアプリで取得したデバイストークンをすべてサーバー側は保存する必要がある

次ページにて今回のサーバーについての環境構築の手順を説明する。


#環境構築の手順
OS:ubuntu 20.04

```bash:
#gitをインストール
sudo apt install git

#gaurunのリリースノートを見て対応するバージョンのgoをダウンロード（ここを間違えてビルドできずにハマった）
Wget https://storage.googleapis.com/golang/go1.13.12.linux-amd64.tar.gz

以下に配置
sudo tar -C /usr/local -xzf go1.13.12.linux-amd64.tar.gz

#環境変数を設定する
export GOPATH=$HOME/go
export GOROOT=/usr/local/go
export PATH=$PATH:/usr/local/go/bin:$GOROOT/bin:$GOPATH/bin


#ホームディレクトリにviで.bash_profileを作成し環境変数のログイン時設定を以下のように記述
echo “GOPATH=$HOME/go”
echo “GOROOT=/usr/local/go”
echo “$PATH:/usr/local/go/bin:$GOROOT/bin:$GOPATH/bin”

#ホームディレクトリにgoのアプリ用のディレクトリを作成
mkdir $HOME/go

#Gauranのインストール：https://github.com/mercari/gaurun
go get -u github.com/mercari/gaurun/...

#glideのインストール
go get -u github.com/Masterminds/glide

Gaurunソースディレクトリに移動
cd /home/username/go/src/github.com/mercari/gaurun

#makeコマンドでビルドする
make
```

上記の環境構築と設定ファイルの編集（今回の設定を次ページにて解説）をした後に、
Gaurunソースディレクトリにて

```bash
bin/gaurun -c conf/gaurun.toml&
```

を実行することで、プッシュ通知用のサーバーが起動する

ライブラリのソースを変更した場合は

```bash
kill プロセス番号
```

コマンドでサーバーを落として、makeコマンドを実行し再度起動させる
設定ファイルのみの変更の場合は、サーバーを落として再起動のみでよい
###設定ファイルの編集例

```bash
vi /home/username/go/src/github.com/mercari/gaurun/gaurun.toml

[core]
port = "1056"　# Gaurun用のポートを任意で設定（今回はデフォルト値）
#port = "unix:/tmp/gaurun.sock"
workers = 8
queues = 8192
notification_max = 100　# 一度にPOSTできる最大の通知の数

[android]
apikey = "YOUR_API_KEY"
enabled = true
timeout = 5 # sec
keepalive_timeout = 30
keepalive_conns = 4
retry_max = 1

[ios]
pem_cert_path = "certificates/cert.pem"　# 証明書を保存したパスに変更（カレントはgaurunディレクトリ）
pem_key_path = "certificates/key.pem"　# 証明書を保存したパスに変更
sandbox = true
enabled = true
timeout = 5
keepalive_timeout = 30
keepalive_conns = 6
retry_max = 1
topic = "jp.yourdomainname"

[log]
access_log = "/var/log/gaurun/access.log"
error_log = "/var/log/gaurun/error.log"
level = "error"
```

#参考
- [プッシュ通知を送信するためのサーバサイド側を構築する](https://qiita.com/kpkpkp/items/0d000adc153e6db47bfc)
- [メルカリのプッシュ配信システムGaurun(オープンソース)を使ってプッシュ送信環境を構築する方法](https://lineocean.com/2017/04/14/82/)