Built with the Phoenix Framework
To start your new Phoenix application you have to:
- Clone this repo, then cd to the new directory
- Install dependencies with
mix deps.get
- (optional) Install npm dependencies to customize the ES6 js/Sass
npm install
- Start Phoenix router with
mix phoenix.server
Now you can visit localhost:4000
from your browser.
http://phoenixchat.herokuapp.com
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> ${body}</p>`)
}
}
$( () => App.init() )
export default App
# lib/chat/endpoint.ex
defmodule Chat.Endpoint do
use Phoenix.Endpoint
socket "/socket", Chat.UserSocket
...
end
# 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
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