No description or website provided.
JavaScript Elixir HTML CSS
Latest commit 31f0c5f Dec 7, 2016 @chrismccord committed on GitHub Merge pull request #39 from benwilson512/master
Cleanup and Update
Permalink
Failed to load latest commit information.
config cleanup Dec 1, 2016
lib cleanup Dec 1, 2016
priv/static cleanup Dec 1, 2016
test Upgrade to 0.10 Mar 11, 2015
web cleanup Dec 1, 2016
.gitignore Upgrade to 0.10 Mar 11, 2015
Procfile Add Procfile Mar 11, 2015
README.md Updated readme with phoenix 0.16 changes Aug 18, 2015
brunch-config.js chore(mix.exs): update to Phoenix 1.1.4 Feb 10, 2016
elixir_buildpack.config Add buildpack back Mar 11, 2015
mix.exs cleanup Dec 1, 2016
mix.lock cleanup Dec 1, 2016
package.json chore(mix.exs): update to Phoenix 1.1.4 Feb 10, 2016

README.md

Simple Chat Example

Built with the Phoenix Framework

To start your new Phoenix application you have to:

  1. Clone this repo, then cd to the new directory
  2. Install dependencies with mix deps.get
  3. (optional) Install npm dependencies to customize the ES6 js/Sass npm install
  4. Start Phoenix router with mix phoenix.server

Now you can visit localhost:4000 from your browser.

Live Demo

http://phoenixchat.herokuapp.com

Example Code

JavaScript

import {Socket, LongPoller} from "phoenix"

class App {

  static init(){
    let socket = new Socket("/socket", {
      logger: ((kind, msg, data) => { console.log(`${kind}: ${msg}`, data) })
    })

    socket.connect({user_id: "123"})
    var $status    = $("#status")
    var $messages  = $("#messages")
    var $input     = $("#message-input")
    var $username  = $("#username")

    socket.onOpen( ev => console.log("OPEN", ev) )
    socket.onError( ev => console.log("ERROR", ev) )
    socket.onClose( e => console.log("CLOSE", e))

    var chan = socket.channel("rooms:lobby", {})
    chan.join().receive("ignore", () => console.log("auth error"))
               .receive("ok", () => console.log("join ok"))
               .after(10000, () => console.log("Connection interruption"))
    chan.onError(e => console.log("something went wrong", e))
    chan.onClose(e => console.log("channel closed", e))

    $input.off("keypress").on("keypress", e => {
      if (e.keyCode == 13) {
        chan.push("new:msg", {user: $username.val(), body: $input.val()})
        $input.val("")
      }
    })

    chan.on("new:msg", msg => {
      $messages.append(this.messageTemplate(msg))
      scrollTo(0, document.body.scrollHeight)
    })

    chan.on("user:entered", msg => {
      var username = this.sanitize(msg.user || "anonymous")
      $messages.append(`<br/><i>[${username} entered]</i>`)
    })
  }

  static sanitize(html){ return $("<div/>").text(html).html() }

  static messageTemplate(msg){
    let username = this.sanitize(msg.user || "anonymous")
    let body     = this.sanitize(msg.body)

    return(`<p><a href='#'>[${username}]</a>&nbsp; ${body}</p>`)
  }

}

$( () => App.init() )

export default App

Endpoint

# lib/chat/endpoint.ex
defmodule Chat.Endpoint do
  use Phoenix.Endpoint

  socket "/socket", Chat.UserSocket
  ...
end

Socket

# web/channels/user_socket.ex
defmodule Chat.UserSocket do
  use Phoenix.Socket

  channel "rooms:*", Chat.RoomChannel

  transport :websocket, Phoenix.Transports.WebSocket
  transport :longpoll, Phoenix.Transports.LongPoll
  ...
end

Channel

defmodule Chat.RoomChannel do
  use Phoenix.Channel
  require Logger

  def join("rooms:lobby", message, socket) do
    Process.flag(:trap_exit, true)
    :timer.send_interval(5000, :ping)
    send(self, {:after_join, message})

    {:ok, socket}
  end

  def join("rooms:" <> _private_subtopic, _message, _socket) do
    {:error, %{reason: "unauthorized"}}
  end

  def handle_info({:after_join, msg}, socket) do
    broadcast! socket, "user:entered", %{user: msg["user"]}
    push socket, "join", %{status: "connected"}
    {:noreply, socket}
  end
  def handle_info(:ping, socket) do
    push socket, "new:msg", %{user: "SYSTEM", body: "ping"}
    {:noreply, socket}
  end

  def terminate(reason, _socket) do
    Logger.debug"> leave #{inspect reason}"
    :ok
  end

  def handle_in("new:msg", msg, socket) do
    broadcast! socket, "new:msg", %{user: msg["user"], body: msg["body"]}
    {:reply, {:ok, %{msg: msg["body"]}}, assign(socket, :user, msg["user"])}
  end
end