Mastodon の bot 等を作るために Streaming API を取得したかったのですが mastodon-api gem には REST API しかなかったのと、具体的なコード例がなかったのとでいくらか調査が必要でした。
その調べた結果を残しておきます。
以下の記事も参考にしました
「PHPでMastodonのStreaming APIを受信する」
http://qiita.com/yyano/items/841f79266faf2dc8b6dc
Streaming API 概要
タイムラインや通知を Websocket で受け取ることができます。
URL は https://(インスタンスのURL)/api/v1/streaming
。
アプリケーションの API アクセストークンとタイムライン種類をクエリで渡すことができます https://(インスタンスのURL)/api/v1/streaming?access_token=(アクセストークン)&stream=[user|public|hashtag]
アクセストークンの取得については他の Mastodon API 解説記事を参照してください。
faye-websocket gem を使う例
以下の gem を使うのでインストールする。
- eventmachine
- faye-websocket
require "eventmachine"
require "faye/websocket"
INSTANCE="(インスタンスのURL)"
TOKEN='(アクセストークン)'
TL='user'
EM.run do
conn = Faye::WebSocket::Client.new(
"wss://#{INSTANCE}/api/v1/streaming?access_token=#{TOKEN}&stream=#{TL}",
)
conn.on :open do |e|
puts "connection success."
end
conn.on :error do |e|
puts "error occured."
end
conn.on :close do |e|
puts "connection close."
end
conn.on :message do |msg|
puts "message receive."
puts msg.data
end
end
websocket-client-simple gem を使う例
必要なのは client だけだとか、eventmachine でネイティブエクステンションをインストールしたくないとかいった場合 websocket-client-simple を使うのが良いです。
以下の gem を使うのでインストールする。
- websocket-client-simple
require 'websocket-client-simple'
INSTANCE="(インスタンスのURL)"
TOKEN='(アクセストークン)'
TL='user'
url = "https://#{INSTANCE}/api/v1/streaming?access_token=#{TOKEN}&stream=#{TL}"
# --- streaming receiver
begin
ws = WebSocket::Client::Simple.connect(url)
rescue => e
puts "error: #{e}"
else
ws.on :message do |msg|
puts "!message"
p msg
end
ws.on :open do
puts "streaming open"
end
ws.on :close do |e|
puts "close"
p e
exit 1
end
ws.on :error do |e|
p e
end
end
loop do
sleep 1
end
簡単な bot のサンプル
メンションで「にゃーん」と言われたら、相手に「にゃーん」と返す簡単な応答 bot です。
Streaming API で通知を監視し、該当のメンションを見つけたら REST API で応答しています。
以下の gem を使用しています
- mastodon-api
- websocket-client-simple
- nokogiri
# coding: utf-8
require 'mastodon'
require 'websocket-client-simple'
require 'nokogiri'
require 'json'
# --- debug switch
VERB = true
# --- config
INSTANCE="(インスタンスのURL)"
TOKEN='(アクセストークン)'
TL='user'
BASEURL = "https://#{INSTANCE}"
STREAMURL = "#{BASEURL}/api/v1/streaming?access_token=#{TOKEN}&stream=#{TL}"
queue = Queue.new
mastodon_client = Mastodon::REST::Client.new(base_url: BASEURL, bearer_token: TOKEN)
# --- action
def answer(request)
result = {}
p request if VERB
contents = Nokogiri::HTML.parse(request["status"]["content"])
text = ''
contents.search('p').children.each do |item|
text += item.text.strip if item.text?
end
#
if text == "にゃーん"
result[:username] = request["account"]["username"]
result[:answer] = "にゃーん"
end
#
p result
return result
end
# --- streaming receiver
begin
ws = WebSocket::Client::Simple.connect(STREAMURL)
rescue => e
puts "error: #{e}"
else
ws.on :message do |msg|
if msg.data.size > 0
begin
toot = JSON.parse(msg.data)
if toot["event"] == "notification"
body = JSON.parse(toot["payload"])
if body["type"] == "mention"
puts "!message" if VERB
res = answer(body)
if res.size > 0
queue.push(res)
end
end
end
rescue => e
puts "content parse error."
puts e
end
end
end
ws.on :open do
puts "streaming open"
end
ws.on :close do |e|
puts "close"
p e
exit 1
end
ws.on :error do |e|
p e
end
end
# --- wait loop and response sender
loop do
action = queue.pop
if action.key?(:username) && action.key?(:answer)
toot = "@#{action[:username]} #{action[:answer]}"
begin
result = mastodon_client.create_status(toot)
p result if VERB
rescue => e
p e
exit 1
end
end
sleep 0.2
end