はじめに
PC初心者でも、スマホしかない人でも、stat.inkにSplatoonの戦績を自動アップロードするdiscord botを作れるようにしたいなというのが、基本的な考えです。
とりあえず無料でstat.inkに戦績を投稿するDiscord Botを作りたい・使いたいという人は、準備方法や使い方についてはGitHub RepositoryのREADMEに詳しく書いたので、そちらをご確認ください。
この記事ではHerokuで稼働するDiscord Botについて工夫した点をお話します。
作成するdiscord botの機能
-
splatnet2stat.py
を利用してstat.inkに複数アカウントの戦績を自動アップロードする。 - discord botを起動後にbotの機能だけでiksm_sessionの取得(自動アップロードの準備)ができる
- bot起動準備を含めてスマホだけですべての作業が完結できる (PCを使える方が便利とはいえ)
問題点と解決策
Herokuではファイル作成・書き込みに制限があります。
- 一時ファイル作成用の
/tmp
にしかファイルを作成できない。(※もともとのファイルは/app
以下に入っている。)- さらに
/tmp
の中も一定時間(最大24時間)ごとにリセットされる。
- さらに
- つまりBot起動後に生成されるファイルを継続的に保存できる場所はない。
これに付随する問題は2点あります。
iksm_sessionの保存場所
discord botを起動後にbotの機能だけでiksm_sessionの取得(自動アップロードの準備)ができる
上の機能の仕様上、iksm_session(厳密にはconfig.txtの中身)はbotをherokuで実行した後に取得されます。
それらのデータを永遠に保存しておくために、今回はHerokuの環境変数を利用しました。
Herokuの環境変数はHeroku管理画面から設定できますが、HerokuのREST APIからも更新できます。つまりHerokuで実行されているBot内から環境変数に出力し、データを継続的に保存することが可能です。
-> 詳しくはPlatform API Reference #config-vars-update
app_name=os.getenv("HEROKU_APP_NAME", "app-splat") #HEROKU_APP_NAME
if app_name=="":
print("環境変数のHEROKU_APP_NAMEが定義されていません。")
return
patch_url = f"https://api.heroku.com/apps/{app_name}/config-vars"
headers= {"Authorization": f"Bearer {os.getenv('HEROKU_APIKEY')}",
"Content-Type":"application/json",
"Accept":"application/vnd.heroku+json; version=3"}
res=requests.patch(patch_url, headers=headers, json=new_envs)
環境変数更新後にdynoは一度再起動されます。
また、注意点としてHerokuの環境変数は合計で32KBまでしか利用できません。
戦績アップロード実行時のconfig.txtの位置
splatnet2statink.py
はiksm_sessionなどが記されたconfig.txtが同じディレクトリに置かれていることを想定されています。
そのままですが、config_path
を書き換えます。
なお、localでの実験も想定して、環境変数はHerokuでデフォルトで設定されるos.getenv("DYNO")
の有無で使い分けます。
## splatnet2statink/iksm.py
config_path="/tmp/config.txt" if os.getenv("DYNO", False) else f"{os.path.dirname(__file__)}/../tmp/config.txt"
## splatnet2statink/splatnet2statink.py
config_path=iksm.config_path
他の問題点として以下があります。
なぜかjson.loads()がstringになる
これは別記事に書きました。-> HerokuでPythonのjson.loads()がstrを返す問題
stringにならない場合もあるので、今はtypeの判別を挟んでいます。
loaded_tmp=json.loads(dumped_string)
loaded_dict=eval(loaded_tmp) if (loaded_tmp)==str else loaded_tmp
GitHub Repository
- GitHub Repository: DiscordBot_Heroku_Stat.ink