Skip to content
This repository has been archived by the owner on Jun 11, 2023. It is now read-only.

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
renatomassaro committed Aug 7, 2018
1 parent 4d252fa commit 7efbfc2
Show file tree
Hide file tree
Showing 6 changed files with 515 additions and 44 deletions.
102 changes: 71 additions & 31 deletions lib/log/model/log_type/macros.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,43 @@ defmodule Helix.Log.Model.LogType.Macros do

defenum LogEnum, @logs

# @spec exists?(term) ::
# boolean
def exists?(log) do
Enum.any?(@logs, fn {valid_log, _} -> valid_log == log end)
end

def new(type, data_params) do
@spec exists?(atom) ::
boolean
def exists?(log_type),
do: Enum.any?(@logs, fn {valid_type, _} -> valid_type == log_type end)

@spec new(type, map) ::
struct
@doc """
Creates a new struct for the given log `type`.
"""
def new(type, data_params),
do: dispatch(type, :new, data_params)

@spec parse(type, map) ::
struct
@doc """
Attempts to parse the potentially unsafe input into a valid LogData.
"""
def parse(type, unsafe_data_params),
do: dispatch(type, :parse, unsafe_data_params)

@spec dispatch(type, atom, term) ::
term
defp dispatch(type, method, param) when not is_list(param),
do: dispatch(type, method, [param])
defp dispatch(type, method, params) do
type
|> get_type_module()
|> apply(:new, [data_params])
|> apply(method, params)
end

end
end

@doc """
Top-level macro used to define a LogType and its underlying LogData.
"""
defmacro log(name, enum_id, do: block) do
module_name =
__CALLER__.module
Expand All @@ -67,6 +89,9 @@ defmodule Helix.Log.Model.LogType.Macros do
end
end

@doc """
Converts the module into a LogData struct.
"""
defmacro data_struct(keys) do
quote do

Expand All @@ -76,17 +101,48 @@ defmodule Helix.Log.Model.LogType.Macros do
end
end

defmacro new(args, do: block) do
@doc """
Creates a new LogData from the given `data` map.
"""
defmacro new(data, do: block) do
quote do

@doc false
def new(unquote(args)) do
def new(unquote(data)) do
unquote(block)
end

end
end

@doc """
Attempts to parse the given unsafe input into a valid LogData.
"""
defmacro parse(data, do: block) do
quote do

@spec parse(term) ::
{:ok, data :: struct}
| :error
@doc false
def parse(map = unquote(data)) when is_map(map) do
try do
{:ok, unquote(block)}
rescue
RuntimeError ->
:error

KeyError ->
:error
end
end

def parse(not_map) when not is_map(not_map),
do: :error

end
end

@doc """
Generates the boilerplate for a n-field log type.
Expand Down Expand Up @@ -116,22 +172,6 @@ defmodule Helix.Log.Model.LogType.Macros do
defmacro gen3(p1, p2, p3),
do: do_gen3(p1, p2, p3)

defmacro parse(args, do: block) do
quote do

@doc false
def parse(unquote(args)) do
try do
{:ok, unquote(block)}
rescue
RuntimeError ->
:error
end
end

end
end

def validate(field_type, field_value) when is_atom(field_type) do
fun = Utils.concat_atom(:validate_, field_type)

Expand Down Expand Up @@ -222,9 +262,9 @@ defmodule Helix.Log.Model.LogType.Macros do
parse(unsafe) do
%__MODULE__{
unquote(f1) =>
validate(unquote(v_f1), Map.get(unsafe, unquote(str_f1))),
validate(unquote(v_f1), Map.fetch!(unsafe, unquote(str_f1))),
unquote(f2) =>
validate(unquote(v_f2), Map.get(unsafe, unquote(str_f2)))
validate(unquote(v_f2), Map.fetch!(unsafe, unquote(str_f2)))
}
end

Expand All @@ -249,11 +289,11 @@ defmodule Helix.Log.Model.LogType.Macros do
parse(unsafe) do
%__MODULE__{
unquote(f1) =>
validate(unquote(v_f1), Map.get(unsafe, unquote(str_f1))),
validate(unquote(v_f1), Map.fetch!(unsafe, unquote(str_f1))),
unquote(f2) =>
validate(unquote(v_f2), Map.get(unsafe, unquote(str_f2))),
validate(unquote(v_f2), Map.fetch!(unsafe, unquote(str_f2))),
unquote(f3) =>
validate(unquote(v_f3), Map.get(unsafe, unquote(str_f3)))
validate(unquote(v_f3), Map.fetch!(unsafe, unquote(str_f3)))
}
end

Expand Down
112 changes: 112 additions & 0 deletions lib/log/websocket/requests/forge.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import Helix.Websocket.Request

request Helix.Log.Websocket.Requests.Forge do
@moduledoc """
`LogForgeRequest` is called when the player wants to forge a log. The forge
operation may either edit an existing log or create a new one.
"""

alias Helix.Log.Model.Log
alias Helix.Log.Model.LogType
alias Helix.Log.Henforcer.Log.Forge, as: LogForgeHenforcer

def check_params(request, socket) do
case request.unsafe["action"] do
"create" ->
check_params_create(request, socket)

"edit" ->
check_params_edit(request, socket)

_ ->
reply_error(request, "bad_action")
end
end

defp check_params_create(request, _socket) do
with \
{:ok, log_info} <-
cast_log_info(request.unsafe["log_type"], request.unsafe["log_data"])
do
params = %{action: :create, log_info: log_info}

update_params(request, params, reply: true)
else
{:error, reason} ->
reply_error(request, reason)
end
end

defp check_params_edit(request, _socket) do
with \
{:ok, log_id} <- Log.ID.cast(request.unsafe["log_id"]),
{:ok, log_info} <-
cast_log_info(request.unsafe["log_type"], request.unsafe["log_data"])
do
params = %{action: :edit, log_id: log_id, log_info: log_info}

update_params(request, params, reply: true)
else
{:error, reason} ->
reply_error(request, reason)

_ ->
bad_request(request)
end
end

def check_permissions(request = %{params: %{action: :create}}, socket) do
gateway_id = socket.assigns.gateway.server_id

case LogForgeHenforcer.can_create?(gateway_id) do
{true, relay} ->
meta = %{gateway: relay.gateway, forger: relay.forger}
update_meta(request, meta, reply: true)

{false, reason, _} ->
reply_error(request, reason)
end
end

def check_permissions(request = %{params: %{action: :edit}}, socket) do
log_id = request.params.log_id
gateway_id = socket.assigns.gateway.server_id
target_id = socket.assigns.destination.server_id

case LogForgeHenforcer.can_edit?(log_id, gateway_id, target_id) do
{true, relay} ->
meta = %{gateway: relay.gateway, forger: relay.forger, log: relay.log}
update_meta(request, meta, reply: true)

{false, reason, _} ->
reply_error(request, reason)
end
end

def handle_request(request, socket) do
end

@spec cast_log_info(String.t, map) ::
{:ok, Log.info}
| {:error, :bad_log_type | :bad_log_data}
defp cast_log_info(unsafe_log_type, unsafe_log_data) do
with \
{:ok, log_type} <- cast_existing_atom(unsafe_log_type),
true <- LogType.exists?(log_type) || {:error, :log_type},
{:ok, log_data} <- LogType.parse(log_type, unsafe_log_data)
do
{:ok, {log_type, log_data}}
else
{:error, :atom_not_found} ->
{:error, :bad_log_type}

{:error, :log_type} ->
{:error, :bad_log_type}

:error ->
{:error, :bad_log_data}
end
end

render_empty()
end
34 changes: 34 additions & 0 deletions lib/server/websocket/channel/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ channel Helix.Server.Websocket.Channel.Server do

alias Helix.Server.State.Websocket.Channel, as: ServerWebsocketChannelState

alias Helix.Log.Websocket.Requests.Forge, as: LogForgeRequest

alias Helix.Network.Websocket.Requests.Browse, as: BrowseRequest

alias Helix.Software.Websocket.Requests.Cracker.Bruteforce,
Expand Down Expand Up @@ -137,6 +139,38 @@ channel Helix.Server.Websocket.Channel.Server do
"""
topic "config.check", ConfigCheckRequest

@doc """
Starts a LogForgeProcess. When forging, the player may want to edit an
existing log, or create a brand new log.
Params (create):
- *log_type: Type of the desired log revision.
- *log_data: Data of the desired log revision.
- *action: Explicitly set action to "create".
Params (edit):
- *log_id: ID of the log that will be edited.
- *log_type: Type of the desired log revision.
- *log_data: Data of the desired log revision.
- *action: Explicitly set action to "edit".
Errors:
Input validation:
- "bad_action" - Action is neither "edit" or "create".
- "bad_log_type" - The given `log_type` is not valid.
- "bad_log_data" - The given `log_data` is not valid for the `log_type`.
Henforcer:
- "forger_not_found" - Player does not have a valid LogForger file.
- "log_not_found" (edit) - The given log ID was not found.
- "log_not_belongs" (edit) - Attempting to edit a log that does not belong to
the open channel.
- base errors
"""
topic "log.forge", LogForgeRequest

@doc """
Updates the player's motherboard. May be used to attach, detach or update the
mobo components.
Expand Down
4 changes: 2 additions & 2 deletions lib/server/websocket/requests/motherboard_update.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ request Helix.Server.Websocket.Requests.MotherboardUpdate do
end
end

def check_detach(request, socket) do
defp check_detach(request, socket) do
with \
true <- socket.assigns.meta.access == :local || :bad_src
do
Expand All @@ -34,7 +34,7 @@ request Helix.Server.Websocket.Requests.MotherboardUpdate do
end
end

def check_update(request, socket) do
defp check_update(request, socket) do
with \
true <- socket.assigns.meta.access == :local || :bad_src,
{:ok, mobo_id} <- Component.ID.cast(request.unsafe["motherboard_id"]),
Expand Down
Loading

0 comments on commit 7efbfc2

Please sign in to comment.