discordbotをPythonからRust🦀に置き換える
そもそも動作してるBotのソースコード
import discord
from os import getenv
intents = discord.Intents.default()
intents.members = True
client = discord.Client(intents=intents)
@client.event
async def on_message(message):
# 送信者がbotかの判断
if message.author.bot:
return
if message.content == "/neko":
await message.channel.send("path/to/cat/image")
if message.content == "/blog":
await message.channel.send("url/to/blog")
#VC開始時に通知
@client.event
async def on_voice_state_update(member, before, after):
# チャンネルへの入室ステータスが変更を検出
if before.channel != after.channel:
# 通知メッセージを書き込むテキストチャンネルを指定
botRoom = client.get_channel(XXXXXXXXX)
# 最初にだれかが入室した時のみに限定
if after.channel is not None and len(after.channel.members) == 1:
bot_msg = await botRoom.send("**[VC開始]** " + member.name + " が話をはじめたよ!\n 参加できるよ:👍\n 無理そう:😭")
await bot_msg.add_reaction('👍')
await bot_msg.add_reaction('😭')
# print(len(after.channel.members))
token = getenv('DISCORD_BOT_TOKEN')
client.run(token)
RustのDiscordbot用ライブラリを使う
exampleが動作するようにする
Client error: Gateway(DisallowedGatewayIntents)
exampleを実行したら
Client error: Gateway(DisallowedGatewayIntents)
とエラーが出てきた
解決方法
同じ現象のissue
DiscordBotの設定を変える必要がある
VCのステータスが変わった時に動作するメソッドをつくる
voice_state_update
でVCの状態が変わったら動作するやつっぽい
Available on crate feature cache only.
とあるのでcacheを作らないといけないっぽい
今の現状
-
Available on crate feature cache only.
とは - voice_state_updateの正しい使い方
解決策
main関数内でこうする
let intents = GatewayIntents::GUILD_VOICE_STATES;
参考にになりそう
updateを検知するために、状態を保存しておく必要がある。cacheを保存する機能をonにしておく必要がある
ここまでできてること
VCへの入手、退出時にメッセージを飛ばす。
理想的な動き
誰も参加していないVCに誰かが参加した時にメッセージを飛ばす。
(VC参加人数が0人から1人になった時)
理想的な動きの実現のために必要なこと
- VCの状態を記録すること
- 0人から1人になった時の判定
discord.pyでは、イベント発火前と後の状態を参照できたが、serenityでは無理っぽい
上記の内容から、serenityの関数や機能でVCの状態は記録できないっぽい。
voice_state_update
のイベントが発火するたびにVCの状態を記録する必要がある。
そして、voice_state_update
は入室、退室どちらでも発火するため、以下のような実装が必要そう
-
voice_state_update
発火時、イベント発火させたメンバーの名前がVC状況を記録する配列になかったら、入室とする。そして、配列にユーザー名を保存。 -
voice_state_update
発火時、イベントを発火させたメンバーの名前が配列にあったら、退室として、配列から一致するユーザー名を削除
配列だと永続化が難しい。だからと言ってDBを使うのはやりすぎな気がするのjsonファイルとかに書き込むとかで永続化をしたい。
VC: hogeからVC: fugaに移動した場合、この想定だと、退室したことになってしまう。
だから、どのVCを識別する必要がある。
VCのチャンネルIDが変わったのであれば、部屋移動と判定できるそう。
幸い、channel_idが取れるので、これが遷移先のchannel_idを示すのであれば、いけそう。
channel_idの仕様は
- VC: Aに参加→AのチャンネルID
- VC AからBに移動→BのチャンネルID
- VC Bから退室→チャンネルIDはNone
つまり、退室時の判定をわざわざ配列から探すとかやらなくて良さそう。Noneだったら、VCに参加してる人数から1を引く。とかできるね
でも、部屋移動を考えるとそれだと、人数が会わなくなる。
Aへ参加、Bへ移動、退室とすると、+1,+1,-1= +1なので移動では加算してはいけない
Cacheと仲良くする
本日のまとめ
voice_state_update
で
チャンネルID、ユーザーIDを見ることで、入室か退室か、移動かなのかわかる。
入室
チャンネルIDは入室先のVC
ユーザーIDは入室したユーザーのID
member_count ++する
移動
チャンネルIDは移動先のチャンネルID
ユーザーは移動したユーザーのID
member_countはそのまま
退出
チャンネルIDはNone
ユーザーIDは退出した人のユーザーID
member_count--
VCの状況を記録する
チャンネルIDが変わった(Noneではない)場合は、ユーザーが別の部屋に移動したことになる。移動と判定するために、前のチャンネルIDとユーザーセットで保持する必要がある。
2022/08/06
連想配列にユーザー,VCのIDを格納して、入室状況を管理する
voice_state_update
でわかったこと
ミュートの切り替えでもイベントが発火する。音声まわりの状態のアップデートだからそれはそう。