スポンサーリンク

2015年6月7日

Phoenix - Channels Guideの実行例を実施

タイトル: PhoenixのChannels Guideの実行例を実施

目的: Phoenix - Channels Guideの実行例を実施する。

実施環境:
OS: Windows8.1
Erlang: Eshell V6.4
Elixir: v1.0.4
Phoenix Framework: v0.13.1
Node.js: v0.12.4

目次:

  1. 概要
  2. 実行例を実施する
  3. 疑問点について

1.概要

1.1
記事を書いた理由。

ちょっと実行例を実施する時に戸惑ったのと、
v0.11.0のソースコードと少し異なる部分があったため。

ソースコードの記述例一式と実行について記事を書きます。

合っているとか妥当とかは置いておくとして。
実行できる!って言うことを優先しています。

1.2
あらかじめ、テスト用のプロジェクトは作成しておいて下さい。

以下、私の実行例
>cd 作業ディレクトリ
>mix phoenix.new phoenix_channels
>y(npm?の使用を聞かれるからyes)
>cd phoenix_channels
>mix phoenix.server
ブラウザからlocalhost:4000にアクセス。

アプリケーション名: phoenix_channels
設定は全てデフォルト

2.実行例を実施する

2.1
ソースコード例の一式~
以下の通り作成した。

/web/router.ex
defmodule PhoenixChannels.Router do
use PhoenixChannels.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", PhoenixChannels do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
socket "/ws", PhoenixChannels do
channel "rooms:*", RoomChannel
end
# Other scopes may use custom stacks.
# scope "/api", PhoenixChannels do
# pipe_through :api
# end
end
view raw router.ex hosted with ❤ by GitHub


/web/channels/room_channel.ex
defmodule PhoenixChannels.RoomChannel do
use Phoenix.Channel
def join("rooms:lobby", auth_msg, socket) do
{:ok, socket}
end
def join("rooms:" <> _private_room_id, _auth_msg, socket) do
{:error, %{reason: "unauthorized"}}
end
def handle_in("new_msg", %{"body" => body}, socket) do
broadcast! socket, "new_msg", %{body: body}
{:noreply, socket}
end
def handle_out("new_msg", payload, socket) do
push socket, "new_msg", payload
{:noreply, socket}
end
end
view raw room_channel.ex hosted with ❤ by GitHub


/web/static/js/app.js
import {Socket} from "phoenix"
// let socket = new Socket("/ws")
// socket.connect()
// let chan = socket.chan("topic:subtopic", {})
// chan.join().receive("ok", chan => {
// console.log("Success!")
// })
let chatInput = $("#chat-input")
let messagesContainer = $("#messages")
let socket = new Socket("/ws")
socket.connect()
let chan = socket.chan("rooms:lobby", {})
chatInput.on("keypress", event => {
if(event.keyCode === 13){
chan.push("new_msg", {body: chatInput.val()})
chatInput.val("")
}
})
chan.on("new_msg", payload => {
messagesContainer.append(`<br/>[${Date()}] ${payload.body}`)
})
chan.join().receive("ok", chan => {
console.log("Welcome to Phoenix Chat!")
})
let App = {
}
export default App
view raw app.js hosted with ❤ by GitHub


/web/templates/page/index.html.eex
<div class="jumbotron">
<h2>Welcome to Phoenix!</h2>
<p class="lead">Most frameworks make you choose between speed and a productive environment. <a href="http://phoenixframework.org">Phoenix</a> and <a href="http://elixir-lang.org">Elixir</a> give you both.</p>
</div>
<div class="row marketing">
<div class="col-lg-6">
<h4>Resources</h4>
<ul>
<li>
<a href="http://phoenixframework.org/docs/overview">Guides</a>
</li>
<li>
<a href="http://hexdocs.pm/phoenix">Docs</a>
</li>
<li>
<a href="https://github.com/phoenixframework/phoenix">Source</a>
</li>
</ul>
</div>
<div class="col-lg-6">
<h4>Help</h4>
<ul>
<li>
<a href="http://groups.google.com/group/phoenix-talk">Mailing list</a>
</li>
<li>
<a href="https://github.com/phoenixframework/phoenix/issues?state=open">Issues</a>
</li>
<li>
<a href="irc://irc.freenode.net/elixir-lang">#elixir-lang on freenode IRC</a>
</li>
<li>
<a href="https://twitter.com/elixirphoenix">@elixirphoenix</a>
</li>
</ul>
</div>
</div>
<div id="messages"></div>
<input id="chat-input" type="text"></input>
view raw index.html hosted with ❤ by GitHub


/web/templates/layout/application.html.eex
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Hello Phoenix!</title>
<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
</head>
<body>
<div class="container" role="main">
<div class="header">
<ul class="nav nav-pills pull-right">
<li><a href="http://www.phoenixframework.org/docs">Get Started</a></li>
</ul>
<span class="logo"></span>
</div>
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= @inner %>
</div>
<!-- /container -->
<!-- Begin page content -->
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
<script>require("web/static/js/app")</script>
</body>
</html>


2.2
いつも通りの実行を行う。
>mix phoenix.server

以下のアドレスへアクセスする。
アドレス: http://localhost:4000

ブラウザのタブをもう一つ追加して同じアドレスへアクセスする。

index.html.eexで記述したインプットフォームへ適当に文字を入力し"Enter"を押す。
どちらのタブにも入力内容が表示されれば、動作確認は問題ない。
参考までに画像を貼っておく・・・参考になるかな~・・・

ブラウザタブ1

ブラウザタブ2

Tips
Javascriptのコンソールログを確認すれば、
"Welcome to Phoenix Chat!"と出力されている。

3.疑問点について

3.1
疑問1

"http://localhost:4000"にアクセスしているのに、
チャネルの"/ws"のパスも動いてるは何故?

また、"http://localhost:4000/hello"と言った時の動作は?
これは検証すればいいが一応・・・

追記(2015/06/07-15:54)
解答
application.html.eexには以下の記述があり、app.jsを実行している。

ソースコード抜粋
----
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
----

app.jsには、以下の記述があり実行されている。

ソースコード抜粋
----
let socket = new Socket("/ws")
socket.connect()
let chan = socket.chan("rooms:lobby", {})
----

つまりべた書きで実行してたわけか・・・そりゃ動きますわ・・・

3.2
疑問2

RoomChannelで"rooms:lobby"とそれ以外の処理を行うjoinコールバック関数を定義している。
"http://localhost:4000"にアクセスした時、
"rooms:lobby"を指定していないのに動作しているのは何故?

デフォルトの設定がなされている?
あるならそれはどうやって設定?ないし処理している?

追記(2015/06/07-15:55)
解答
疑問1での解答より、べた書きで実行しているため。
app.jsに書いてある。

3.3
疑問3

例えば、チャネルのルーティングを二つ作成したとする。
"/ws1"、"/ws2"と言ったパスで。

今回の実行では、
"http://localhost:4000"にアクセスした時、
"/ws"のパスも動いているが、二つ定義している時は、どちらも動くのか?

追記(2015/06/07-15:56)
解答
疑問1での解答より、べた書きで実行しているため、
定義しても動作しないと見受けられる。

っといった疑問点がありますね。
私が調査できてないだけ、読み取れていないだけと言うこともありますが、
この辺りを把握しないと実際のアプリケーションには組み込めないです。

今後の調査で把握できれば、また別記事を上げますね。

追記(2015/06/07-15:58)
全て同じ解答に行き着くという・・・ソースを読めって話ですね~
ようは、HTTPの通信とWebSocketの関係が分かってなかったわけですね・・・この私が!!
WebSocketの説明について参考までに・・・
参考1: https://www.atled.jp/jireinavi/develop/websocket/
参考2: south37のブログ - WebSocketについて調べてみた。

以上!!

参考にさせて頂いたサイト様
Phoenix - Channels Guide
Phoenix Framework - Channel 日本語翻訳

管理人の独り言~
Channel Routesについて別記事を上げてますので、良かった一緒にどうぞ~
続!Phoenixのルーティング(Router)について分かったこと

これにて、Elixir(Phoenix)強化週間中の記事終わり~
今後もElixirはやっていきますが。
今回ので何とか基礎は習得できたかな?
それらを組み合わせて掲示板もどきの作成にでも入りますか~

記事を書いてから気付いた。
"Tying it all together"って書いてあんじゃん・・・おおうorz

自分用メモ・・・
httpの通信は、"http://・・・"
WebSocketの通信は、"ws://・・・"

http://とws://は両立して流せるけど、別の通信ってことか。

しかし、通信の流れを追ってみたが・・・
/wsは追えるが、rooms:lobbyが追えない・・・何でだろう?
httpとWebSokectの通信混じると、私の貧弱な頭では分からないいいいい・・・
参考: http://d.hatena.ne.jp/uuwan/20130121/p1

人気の投稿