Skip to content

Instantly share code, notes, and snippets.

@landongn
Created December 7, 2016 08:51
Show Gist options
  • Save landongn/9dac005a4ec440a8d5d884a7165f3d32 to your computer and use it in GitHub Desktop.
Save landongn/9dac005a4ec440a8d5d884a7165f3d32 to your computer and use it in GitHub Desktop.
defmodule Server.CharacterChannel do
use Server.Web, :channel
alias Phoenix.View
alias Server.CharacterView
alias Server.Repo
alias Server.Player
alias Server.Character
alias Ecto.Query
def join("character", _payload, socket) do
{:ok, socket}
end
def handle_in("game.zone.character.list", _, socket) do
q = Character
|> Query.where(player_id: ^socket.user_id)
results = Repo.all(q)
push socket, "msg", %{
opcode: "game.zone.character.list",
characters: results,
message: View.render_to_string(CharacterView, "character-list.html", %{characters: results})
}
{:noreply, socket}
end
def handle_in("game.zone.character.create", payload, socket) do
{:noreply, socket}
end
def handle_in("game.zone.character.new", payload, socket) do
{:noreply, socket}
end
def handle_in("game.zone.character.delete", payload, socket) do
{:noreply, socket}
end
end
[error] GenServer #PID<0.400.0> terminating
** (KeyError) key :user_id not found in: %Phoenix.Socket{assigns: %{}, channel: Server.CharacterChannel, channel_pid: #PID<0.400.0>, endpoint: Server.Endpoint, handler: Server.UserSocket, id: nil, joined: true, pubsub_server: Server.PubSub, ref: "15", serializer: Phoenix.Transports.WebSocketSerializer, topic: "character", transport: Phoenix.Transports.WebSocket, transport_name: :websocket, transport_pid: #PID<0.396.0>}
(server) web/channels/character_channel.ex:17: Server.CharacterChannel.handle_in/3
(phoenix) lib/phoenix/channel/server.ex:226: anonymous fn/4 in Phoenix.Channel.Server.handle_info/2
(stdlib) gen_server.erl:601: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:667: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: %Phoenix.Socket.Message{event: "game.zone.character.list", payload: %{}, ref: "15", topic: "character"}
State: %Phoenix.Socket{assigns: %{}, channel: Server.CharacterChannel, channel_pid: #PID<0.400.0>, endpoint: Server.Endpoint, handler: Server.UserSocket, id: nil, joined: true, pubsub_server: Server.PubSub, ref: nil, serializer: Phoenix.Transports.WebSocketSerializer, topic: "character", transport: Phoenix.Transports.WebSocket, transport_name: :websocket, transport_pid: #PID<0.396.0>}
defmodule Server.UserSocket do
use Phoenix.Socket
## Channels
channel "zone", Server.ZoneChannel
channel "world:system", Server.WorldChannel
channel "messaging", Server.MessagingChannel
channel "combat", Server.CombatChannel
channel "forest", Server.ForestChannel
channel "village", Server.VillageChannel
channel "character", Server.CharacterChannel
## Transports
transport :websocket, Phoenix.Transports.WebSocket
# Socket params are passed from the client and can
# be used to verify and authenticate a user. After
# verification, you can put default assigns into
# the socket that will be set for all channels, ie
#[]
# {:ok, assign(socket, :user_id, verified_user_id)}
#
# To deny connection, return `:error`.
#
# See `Phoenix.Token` documentation for examples in
# performing token verification on connect.
def connect(_params, socket) do
{:ok, socket}
end
# Socket id's are topics that allow you to identify all sockets for a given user:
#
# def id(socket), do: "users_socket:#{socket.assigns.user_id}"
#
# Would allow you to broadcast a "disconnect" event and terminate
# all active sockets and channels for a given user:
#
# Server.Endpoint.broadcast("users_socket:#{user.id}", "disconnect", %{})
#
# Returning `nil` makes this socket anonymous.
def id(_socket), do: nil
end
defmodule Server.WorldChannel do
use Server.Web, :channel
require Logger
require Comeonin.Bcrypt
alias Server.Player
alias Phoenix.View
alias Server.WorldView
alias Server.CharacterView
alias Server.Auth
def join("world:system", _, socket) do
msg = View.render_to_string(WorldView, "welcome_message.html", %{})
{:ok, %{message: msg, opcode: "game.client.connect", actions: ["enter"]}, socket}
end
def handle_in("motd", _, socket) do
msg = View.render_to_string(WorldView, "motd.html", %{})
push socket, "msg", %{message: msg, opcode: "game.client.motd", actions: ["enter"]}
{:noreply, socket}
end
def handle_in("ident", _, socket) do
push socket, "msg", %{
message: View.render_to_string(WorldView, "auth_challenge.html", %{}),
opcode: "game.client.ident-challenge",
actions: ["e"]
}
{:noreply, socket}
end
def handle_in("email-ident", _, socket) do
push socket, "msg", %{
message: View.render_to_string(WorldView, "auth-email.html", %{}),
opcode: "game.client.ident-email",
actions: ["enter"]
}
{:noreply, socket}
end
def handle_in("email-identify", %{"email" => payload}, socket) do
case Server.Repo.get_by Player, email: payload do
record when record != nil ->
push socket, "msg", %{
message: View.render_to_string(WorldView, "password.html", record),
opcode: "game.client.ident.validuser"
}
nil ->
push socket, "msg", %{
message: View.render_to_string(WorldView, "user-not-found.html", %{email: payload}),
opcode: "game.client.ident.notfound",
actions: ["enter"]
}
end
{:noreply, socket}
end
def handle_in("password-identify", %{"password" => password, "email" => email}, socket) do
case Server.Repo.get_by Player, email: email do
player when player != nil ->
case Comeonin.Bcrypt.checkpw(password, player.password) do
true ->
token = Phoenix.Token.sign(Server.Endpoint, "player_id", player.id)
updated = Ecto.Changeset.change player, secret: token
Server.Repo.update updated
assign(socket, :user_id, player.id)
assign(socket, :token, token)
push socket, "data", %{
opcode: 'game.client.session.create',
token: token,
user_id: player.id
}
push socket, "msg", %{
message: View.render_to_string(CharacterView, "character-select.html", %{}),
opcode: "game.zone.character.select",
actions: []
}
_ ->
push socket, "msg", %{
message: View.render_to_string(WorldView, "auth_challenge.html", %{}),
opcode: "game.client.ident-challenge",
actions: ["e"]
}
end
nil ->
changeset = Player.changeset(%Player{}, %{
email: email, password: Comeonin.Bcrypt.hashpwsalt(password)
})
case changeset.valid? do
true ->
case Server.Repo.insert(changeset) do
{:ok, player} ->
token = Phoenix.Token.sign(Server.Endpoint, "player_id", player.id)
updated = Ecto.Changeset.change player, secret: token
Server.Repo.update updated
assign(socket, :user_id, player.id)
assign(socket, :token, token)
push socket, "data", %{
opcode: 'game.client.session.create',
token: token,
user_id: player.id,
}
push socket, "msg", %{
message: View.render_to_string(CharacterView, "character-select.html", %{}),
opcode: "game.zone.character.select",
actions: []
}
{:error, changeset} ->
push socket, "msg", %{opcode: "game.client.ident.error"}
end
false ->
push socket, "msg", %{
opcode: "game.client.ident.bad-password",
message: "That password didn't work. Sorry.",
actions: []
}
end
end
{:noreply, socket}
end
# # Channels can be used in a request/response fashion
# # by sending replies to requests from the client
# def handle_in("ping", payload, socket) do
# {:reply, {:ok, payload}, socket}
# end
# # It is also common to receive messages from the client and
# # broadcast to everyone in the current topic (world:lobby).
# def handle_in("shout", payload, socket) do
# broadcast socket, "shout", payload
# {:noreply, socket}
# end
# Add authorization logic here as required.
# defp authorized?(_payload) do
# true
# end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment