LoginSignup
1
1

More than 5 years have passed since last update.

ElixirのPhoenixChannelClientでTwitterを再配信する

Last updated at Posted at 2018-03-16

 以前の記事「Phoenix Channelとelm-phoenixについて - Qiita」でElmクライアントからPhoenix channelを利用する方法を示しました。この時のexampleはチャットシステムでした。以下のような会話の流れになります。

Elmクライアント  <---> Phoenix Channel <---> Elmクライアント

 今回はこのチャットシステムをそのまま変更せずに利用して、これにElixirクライアントを加えてみたいと思います。Elixirクライアントは、ブラウザアプリではないので、TwitterからTweetを拾って、そのままchannelに流したいと思います。

Elmクライアント  <--- Phoenix Channel <--- Elixirクライアント <---Twitter Stream

 ElixirとTwitterについても過去の記事「ElixirでTwitterを検索する - Qiita」を参考にします。

 さて、Elixir を Phoenix channelのクライアントとして使うために、PhoenixChannelClientというライブラリをを選択しました。同じようなライブラリがいくつかありましたが、ヤマカンで使いやすそうなものを選びました。いい加減です。

 プロジェクトを開始します。

mix new channel_client
cd channel_client

 次にapplication environmentを利用して初期設定を行います。すなわちmix newで作成されたconfig/config.exsファイルにTwitter APIのキーを設定します。以下の項目をファイルの末尾に追加します。

config/config.exs
#
config :extwitter, :oauth, [
   consumer_key: "xxxxx",
   consumer_secret: "xxxxx",
   access_token: "xxxxx",
   access_token_secret: "xxxxx"
]
#

 さて、mix.exsにphoenixchannelclientと、twitter関連のライブラリを追加します。

mix.exs
#
defp deps do
  [
    {:phoenixchannelclient, "~> 0.1.0"},
    {:oauther, "~> 1.1"},
    {:extwitter, "~> 0.8"}
  ]
end
#

 次のコマンドでライブラリをインストールします。

mix deps.get

 これで準備が整いました。
 別端末を開いて「Phoenix Channelとelm-phoenixについて - Qiita」のチャットサーバを立ち上げます。

iex -S mix phx.server

 ブラウザからこのサーバにアクセスして、チャットウィンドウを開きます。User1でログインします。

image.png

さて元のElixirの端末に戻り、シェルを立ち上げます。

iex -S mix

 シェルが立ち上がったら、以下のコマンドを順番に入力します。特にプログラムファイルは書きません。

{:ok, pid} = PhoenixChannelClient.start_link()

{:ok, socket} = PhoenixChannelClient.connect(pid,
  host: "localhost",
  port: 4000,
  path: "/socket/websocket",
  secure: false,
  heartbeat_interval: 30_000)

channel = PhoenixChannelClient.channel(socket, "room:lobby", %{user_name: "User9"})

PhoenixChannelClient.join(channel) 

pid = spawn(fn ->
  stream = ExTwitter.stream_filter(track: "ラーメン")
  for tweet <- stream do
    IO.puts tweet.text
    PhoenixChannelClient.push(channel, "new_msg", %{msg: tweet.text})
  end
end)

 socketを作り、channelを作り、joinし、twitterのstreamをリッスンし、「ラーメン」というキーワードを含んでいたら、channelにチャットを書き込みます。ポイントは「"room:lobby"」というtopicに「 %{user_name: "User9"}」でjoinしていることです。サーバ側のchannelにインターフェースを合わせています。これだけで既存のチャットシステムに参加できてしまいます。

 以下が、Elixirクライアントの端末のキャプチャーです。IO.puts tweet.text の出力が流れています。

[root@www13134uf channel_client]# iex -S mix
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:3:3] [ds:3:3:10] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.7.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, pid} = PhoenixChannelClient.start_link()
{:ok, #PID<0.164.0>}
iex(2)> {:ok, socket} = PhoenixChannelClient.connect(pid,
...(2)>   host: "localhost",
...(2)>   port: 4000,
...(2)>   path: "/socket/websocket",
...(2)>   secure: false,
...(2)>   heartbeat_interval: 30_000)
{:ok, %PhoenixChannelClient.Socket{server_name: #PID<0.164.0>}}
iex(3)> channel = PhoenixChannelClient.channel(socket, "room:lobby", %{user_name
: "User9"})
%PhoenixChannelClient.Channel{
  params: %{user_name: "User9"},
  socket: %PhoenixChannelClient.Socket{server_name: #PID<0.164.0>},
  topic: "room:lobby"
}
iex(4)> PhoenixChannelClient.join(channel)
{:ok, %{}}
iex(5)> pid = spawn(fn ->
...(5)>   stream = ExTwitter.stream_filter(track: "ラーメン")
...(5)>   for tweet <- stream do
...(5)>     IO.puts tweet.text
...(5)>     PhoenixChannelClient.push(channel, "new_msg", %{msg: tweet.text})
...(5)>   end
...(5)> end)
#PID<0.206.0>
すき焼き
焼肉
ラーメン
寿司
てりたま
フライドポテト
卵かけご飯
焼き鳥丼
唐揚げ
カツ丼
ピザ

食べるのを控えてる食べ物たちであり今食べたいもの?ゐい陲
カラオ皺ヒカ€オ・邁ハーーォー蟆トーメッルア€ア族銧サーォーアー・ニーユーサーッ・
サ床ァーューーケマー゙キニーユーサーー・エー゚ー擴擴擴・
 きちゃった… (@ ラーメン きずな - @ra_men_kizuna_ in 岡山市, 岡山県) https://t.co/9aPvqSFKPr
RT @purichannel: 初めて煮干しのまぜそば食べてみた!旨すぎ!

https://t.co/NDnFmWldSh

柏のラーメン屋!!

#まぜそば
#ラーメン
#煮干し https://t.co/XOEWRPxUYk
らーめん穀雨@渋谷・ワンタンめん (3個入り) 。
喧騒から離れた、路地裏にひっそり佇むお店。醤油系の清湯スープに、中細ストレート麺。ワンタンは一口サイズで、味は勿論、見た目も品を感じる一杯。\830。
#ラーメン #ramen https://t.co/x2EgAYaK1Z
iex(6)>

 以下が、Elixirクライアントの端末のキャプチャーです。 PhoenixChannelClient.push(channel, "new_msg", %{msg: tweet.text}) の書き込みが自動的に流れています。

image.png

 これはブラウザクライアントが増えても、すべてにTweetsが配信されます。ブラウザ同士でチャットもできます。チャットシステムにElixirクライアントを加えて、Twetterの書き込みを流しているだけですから。これで完成です。

 最後に、本プログラムには必要ないものですが、channerの双方向性も押さえておきたいと思います。Elixirクライアントでもチャットメッセージを受け取るためには、iexシェル上で以下のコマンドを打つ必要があります。これを設定すれば、ブラウザクライアントから送られたチャットがiex上に流れるようになります。

receive do
  {"new_msg", message } -> IO.puts (message["user_name"] <>": "<> message["msg"])
  :close -> IO.puts("closed")
  {:error, error} -> IO.inspect error
end

 今回の話はこれで終わりです。今回の記事は、半年以上前に書いた記事「Meteor and Reactによるリアクティブシステム「ラーメン野郎を追いかけろ! @ Twitter」を作ってみた - Qiita」がモティーフになっています。このようなリアルタイムシステムを作るのに、Meteorは素晴らしいプラットフォームを提供してくれました。サーバ側にMongoDB、クライアント側にmini-MongoDBを配して、透過的に同期を取るシステムはシンプルでとても魅力的でした。GoogleのFirebaseを除いては、これに代わるものは知りません。今回は、Phoenix channelを使えば同じようなシステムが構築できるのではないかと思い、試してみました。しかもPhoenix channelはMeteorにない魅力もあります。次回はクライアントをReactに変えて、もっと「ラーメン野郎を追いかけろ」と同じようなものを作りたいと思います。地図とTweetを表示したい。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1