Packages
riptide
0.5.0-beta4
0.5.2
0.5.1
0.5.0-beta9
0.5.0-beta8
0.5.0-beta7
0.5.0-beta6
0.5.0-beta5
0.5.0-beta4
0.5.0-beta3
0.5.0-beta2
0.5.0-beta11
0.5.0-beta10
0.5.0-beta
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.3.0-bd63a38
0.2.79
0.2.78
0.2.74
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A data first framework for building realtime applications
Current section
Files
Jump to
Current section
Files
lib/riptide/connection/processor.ex
defmodule Riptide.Processor do
@moduledoc false
require Logger
def init(state) do
Map.merge(
%{
counter: 0,
pending: %{},
format: Riptide.Format.JSON,
handlers: [],
data: %{}
},
state
)
end
def send_call(action, body, from, state) do
data =
%{
type: "call",
key: state.counter,
action: action,
body: body
}
|> format(state)
{:reply, data,
%{state | counter: state.counter + 1, pending: Map.put(state.pending, state.counter, from)}}
end
def send_cast(action, body, state) do
data =
%{
type: "cast",
action: action,
body: body
}
|> format(state)
{:reply, data, state}
end
def process_data(msg, state) do
msg
|> state.format.decode()
|> case do
{:ok,
%{
"type" => "cast",
"action" => action,
"body" => body
}} ->
case trigger_handlers(state, :handle_cast, [action, body, state.data]) do
{:noreply, next} ->
{:noreply, %{state | data: next}}
{:reply, {action, body}, next} ->
{:reply, cast(action, body, state), %{state | data: next}}
nil ->
{:noreply, state}
end
{:ok,
%{
"type" => "call",
"key" => key,
"action" => action,
"body" => body
}} ->
case trigger_handlers(state, :handle_call, [action, body, state.data]) do
{:reply, value, next} ->
{:reply, reply(key, value, state), %{state | data: next}}
{:error, error, next} ->
{:reply, error(key, error, state), %{state | data: next}}
{:error, error} ->
{:reply, error(key, error, state), state}
nil ->
{:reply, error(key, [:not_implemented, action], state), state}
end
{:ok,
%{
"type" => type,
"key" => key,
"body" => body
}}
when type in ["error", "reply"] ->
case Map.get(state.pending, key) do
nil ->
{:noreply, state}
pid ->
send(pid, {:riptide_response, type, body})
{:noreply, %{state | pending: Map.delete(state.pending, key)}}
end
_ ->
{:noreply, state}
end
end
def process_info(msg, state) do
case trigger_handlers(state, :handle_info, [msg, state.data]) do
{:noreply, next} ->
{:noreply, %{state | data: next}}
{:reply, {action, body}, next} ->
{:reply, cast(action, body, state), %{state | data: next}}
nil ->
{:noreply, state}
end
end
def trigger_handlers(state, fun, args) do
Enum.find_value(
state.handlers ++
[
Riptide.Handler.Ping,
Riptide.Handler.Mutation,
Riptide.Handler.Query,
Riptide.Handler.Subscribe,
Riptide.Handler.Store
],
fn mod ->
try do
apply(mod, fun, args)
rescue
e ->
:error
|> Exception.format(e, __STACKTRACE__)
|> Logger.error(crash_reason: {e, __STACKTRACE__})
{:error, inspect(e)}
catch
_, e ->
:throw
|> Exception.format(e, __STACKTRACE__)
|> Logger.error(crash_reason: {e, __STACKTRACE__})
{:error, inspect(e)}
end
end
)
end
def reply(key, body, state) do
%{
type: "reply",
key: key,
body: body
}
|> format(state)
end
def cast(action, body, state) do
%{
type: "cast",
action: action,
body: body
}
|> format(state)
end
def error(key, body, state) do
%{
type: "error",
key: key,
body: body
}
|> format(state)
end
def format(msg, state) do
msg
|> state.format.encode()
|> case do
{:ok, result} -> result
end
end
end