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

Commit

Permalink
Merge 26100c3 into b74ea5a
Browse files Browse the repository at this point in the history
  • Loading branch information
renatomassaro committed Jun 25, 2018
2 parents b74ea5a + 26100c3 commit 124dcff
Show file tree
Hide file tree
Showing 106 changed files with 3,177 additions and 548 deletions.
1 change: 1 addition & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ config :helix,
Helix.Entity.Repo,
Helix.Log.Repo,
Helix.Network.Repo,
Helix.Notification.Repo,
Helix.Universe.Repo,
Helix.Process.Repo,
Helix.Server.Repo,
Expand Down
10 changes: 10 additions & 0 deletions config/notification/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use Mix.Config

config :helix, Helix.Notification.Repo,
priv: "priv/repo/notification",
pool_size: 3,
adapter: Ecto.Adapters.Postgres,
username: System.get_env("HELIX_DB_USER") || "postgres",
password: System.get_env("HELIX_DB_PASS") || "postgres",
hostname: System.get_env("HELIX_DB_HOST") || "localhost",
types: HELL.PostgrexTypes
6 changes: 6 additions & 0 deletions config/notification/dev.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use Mix.Config

prefix = System.get_env("HELIX_DB_PREFIX") || "helix"

config :helix, Helix.Notification.Repo,
database: prefix <> "_dev_notification"
10 changes: 10 additions & 0 deletions config/notification/prod.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use Mix.Config

prefix = "${HELIX_DB_PREFIX}"

config :helix, Helix.Notification.Repo,
pool_size: "${HELIX_DB_POOL_SIZE}",
username: "${HELIX_DB_USER}",
password: "${HELIX_DB_PASS}",
hostname: "${HELIX_DB_HOST}",
database: prefix <> "_prod_notification"
8 changes: 8 additions & 0 deletions config/notification/test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use Mix.Config

prefix = System.get_env("HELIX_DB_PREFIX") || "helix"

config :helix, Helix.Notification.Repo,
pool: Ecto.Adapters.SQL.Sandbox,
database: prefix <> "_test_notification",
ownership_timeout: 90_000
6 changes: 3 additions & 3 deletions events.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@
"Steppable (custom)"
]
},
"Notification": {
"Publication": {
"receives": ["All"],
"emits": ["Notificable (custom)"]
"emits": ["Publishable (custom)"]
}
},
"flows": {
Expand Down Expand Up @@ -173,7 +173,7 @@
"File.Install.Processed",
"File.Transfer.Processed"
],
"notificable": [
"publishable": [
"Log.Created",
"Log.Modified",
"Log.Deleted",
Expand Down
8 changes: 4 additions & 4 deletions graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

handlers = events["handlers"]
flows = events["flows"]
notificable = events["notificable"]
publishable = events["publishable"]
missions = events["missions"]
process_conclusion = events["process_conclusion"]

def is_notificable(name):
return name in notificable
def is_publishable(name):
return name in publishable

def node_event(g, name):
color = 'lightblue4' if is_notificable(name) else 'lightblue2'
color = 'lightblue4' if is_publishable(name) else 'lightblue2'
g.node(name, shape='box', color=color, style='filled')

def node_handler(g, name):
Expand Down
40 changes: 37 additions & 3 deletions lib/account/websocket/channel/account.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import Helix.Websocket.Channel

channel Helix.Account.Websocket.Channel.Account do
@moduledoc """
Channel to notify an user of an action that affects them.
Two-way channel to receive requests and send out publications to an user about
actions that affects them.
"""

alias Helix.Account.Websocket.Channel.Account.Join, as: AccountJoin
Expand All @@ -13,6 +14,7 @@ channel Helix.Account.Websocket.Channel.Account do
alias Helix.Network.Websocket.Requests.Bounce.Create, as: BounceCreateRequest
alias Helix.Network.Websocket.Requests.Bounce.Update, as: BounceUpdateRequest
alias Helix.Network.Websocket.Requests.Bounce.Remove, as: BounceRemoveRequest
alias Helix.Notification.Websocket.Requests.Read, as: NotificationReadRequest
alias Helix.Software.Websocket.Requests.Virus.Collect, as: VirusCollectRequest
alias Helix.Story.Websocket.Requests.Email.Reply, as: EmailReplyRequest

Expand Down Expand Up @@ -59,7 +61,7 @@ channel Helix.Account.Websocket.Channel.Account do
topic "client.setup", ClientSetupProxyRequest

@doc """
Notifies the backend that `action` has been performed by the player.
Notifies Helix that `action` has been performed by the player.
Params:
*action: Action performed by the player. [0]
Expand Down Expand Up @@ -202,10 +204,42 @@ channel Helix.Account.Websocket.Channel.Account do
Input:
+ base errors
"""
topic "bounce.remove", BounceRemoveRequest

@doc """
Marks one (or all) notifications as read.
Params:
- notification_id: Which notification to mark as read. See [1].
- class: Which class the notification belongs to. See [1].
[1] - This request can be used to mark a single notification as read, or all
notifications within a class as read. If the `notification_id` param is
given, we assume only that notification must be marked as read. On the other
hand, if only `class` is given, we assume all notifications of that class
shall be marked as read. Only one of them must be given. If both are given,
we blow up and assume the client did not read this documentation.
Returns: :ok
Events:
- notification_read_event: Emitted when notification(s) are successfully read.
Errors:
Henforcer:
- notification_not_found: The given `notification_id` does not exist.
- notification_not_belongs: Client attempted to read a notification that
belongs to another user.
Input:
- read_the_docs: Client did not read the docs. See [1].
- bad_class: The given class is not valid.
+ base errors
"""
topic "notification.read", NotificationReadRequest

@doc """
Collects money off of active viruses.
Expand Down
1 change: 1 addition & 0 deletions lib/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ defmodule Helix.Application.DomainsSupervisor do
supervisor(Helix.Event.Supervisor, []),
supervisor(Helix.Log.Supervisor, []),
supervisor(Helix.Network.Supervisor, []),
supervisor(Helix.Notification.Supervisor, []),
supervisor(Helix.Process.Supervisor, []),
supervisor(Helix.Server.Supervisor, []),
supervisor(Helix.Software.Supervisor, []),
Expand Down
4 changes: 2 additions & 2 deletions lib/client/websocket/requests/setup.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ proxy_request Helix.Client.Websocket.Requests.Setup do
select_backend(_request, socket) do
case socket.assigns.client do
:web1 ->
Web1SetupRequest
{:ok, Web1SetupRequest}

_ ->
false
{:error, "request_not_implemented_for_client"}
end
end
end
24 changes: 24 additions & 0 deletions lib/core/validator/model.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Helix.Core.Validator.Model do
@moduledoc """
This is a helper module to create a syntactic sugar for Helix models that
implement verifications for the `Helix.Core.Validator`.
"""

@doc """
Pure syntactic sugar.
"""
defmacro validator(do: block) do
parent_module = __CALLER__.module
module_name = Module.concat(parent_module, "Validator")

quote do

defmodule unquote(module_name) do
alias unquote(parent_module)

unquote(block)
end

end
end
end
14 changes: 13 additions & 1 deletion lib/core/validator/validator.ex
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
defmodule Helix.Core.Validator do

alias Helix.Notification.Model.Notification

@type input_type ::
:password
| :hostname
| :bounce_name
| :reply_id
| :notification_id

@type validated_inputs ::
String.t
| Notification.Validator.validated_inputs

@regex_hostname ~r/^[a-zA-Z0-9-_.@#]{1,20}$/

@spec validate_input(input :: String.t, input_type, opts :: term) ::
{:ok, validated_input :: String.t}
{:ok, validated_inputs}
| :error
@doc """
This is a generic function meant to validate external input that does not
Expand All @@ -33,6 +40,11 @@ defmodule Helix.Core.Validator do
def validate_input(input, :reply_id, _),
do: validate_reply_id(input)

def validate_input(input, :notification_id, opts),
do: Notification.Validator.validate_id(input, opts)

# Implementations

defp validate_hostname(v) when not is_binary(v),
do: :error
defp validate_hostname(v) do
Expand Down
18 changes: 15 additions & 3 deletions lib/event/dispatcher.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ defmodule Helix.Event.Dispatcher do

use HELF.Event

alias Helix.Event.NotificationHandler
alias Helix.Event.PublicationHandler

alias Helix.Core.Listener.Event.Handler.Listener, as: ListenerHandler
alias Helix.Account.Event, as: AccountEvent
Expand All @@ -47,6 +47,8 @@ defmodule Helix.Event.Dispatcher do
alias Helix.Log.Event.Handler, as: LogHandler
alias Helix.Network.Event, as: NetworkEvent
alias Helix.Network.Event.Handler, as: NetworkHandler
alias Helix.Notification.Event, as: NotificationEvent
alias Helix.Notification.Event.Handler, as: NotificationHandler
alias Helix.Process.Event, as: ProcessEvent
alias Helix.Process.Event.Handler, as: ProcessHandler
alias Helix.Server.Event, as: ServerEvent
Expand All @@ -61,12 +63,14 @@ defmodule Helix.Event.Dispatcher do
# Global handlers
##############################################################################

all_events NotificationHandler, :notification_handler
all_events ListenerHandler, :listener_handler

all_events LogHandler.Log, :handle_event,
skip: [LogEvent.Log.Created]

all_events ListenerHandler, :listener_handler
all_events NotificationHandler.Notification, :notification_handler

all_events PublicationHandler, :publication_handler

##############################################################################
# Account events
Expand Down Expand Up @@ -127,6 +131,14 @@ defmodule Helix.Event.Dispatcher do
ProcessHandler.TOP,
:object_handler

##############################################################################
# Notification events
##############################################################################

# All
event NotificationEvent.Notification.Added
event NotificationEvent.Notification.Read

##############################################################################
# Log events
##############################################################################
Expand Down
1 change: 1 addition & 0 deletions lib/event/event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ defmodule Helix.Event do
import Helix.Event.Listenable.Flow
import Helix.Event.Loggable.Flow
import Helix.Event.Notificable.Flow
import Helix.Event.Publishable.Flow

unquote(block)
end
Expand Down
80 changes: 18 additions & 62 deletions lib/event/notificable/flow.ex
Original file line number Diff line number Diff line change
@@ -1,83 +1,39 @@
defmodule Helix.Event.Notificable.Flow do

import HELL.Macros
alias Helix.Notification.Model.Code, as: NotificationCode

alias Phoenix.Socket
alias HELL.HETypes
alias Helix.Event
alias Helix.Event.Notificable

@type event_id :: HETypes.uuid

@doc """
Top-level macro for an event that wants to implement the Notificable protocol.
"""
defmacro notify(do: block) do
defmacro notification(do: block) do
quote do

defimpl Helix.Event.Notificable do
@moduledoc false

@event nil
@class nil
@code nil

unquote(block)

@event || raise "You must set an event name with @event"
@class || raise "You must set a notification class with @class"
@code || raise "You must set a notification code with @code"

NotificationCode.code_exists?(@class, @code)
|| raise "Notification not found: #{inspect {@class, @code}}"

@doc """
Returns the event name as a string
Returns notification data (tuple with class and code)
"""
def get_event_name(_event) do
to_string(@event)
def get_notification_data(_event) do
{@class, @code}
end
end

end
end

@spec generate_event(struct, Socket.t) ::
{:ok, %{data: term, event: String.t, meta: Event.Meta.rendered}}
| :noreply
@doc """
Attempts to generate the payload for that event. If the implementation of the
Notificable protocol returns a valid payload (i.e. it wants to notify that
specific user), then we'll set up the event metadata and return it ready to
be sent to the player.
"""
def generate_event(event, socket) do
case Notificable.generate_payload(event, socket) do
{:ok, data} ->
payload =
%{
data: data,
event: Notificable.get_event_name(event),
meta: Event.Meta.render(event)
}
# Fallbacks

{:ok, payload}
@doc false
def extra_params(_) do
%{}
end
end

noreply ->
noreply
end
end

@spec add_event_identifier(struct) ::
struct
@doc """
Adds the event unique identifier.
Keep in mind that this unique identifier is for the *event*, i.e. the fact
that something happened. If this event gets broadcasted to multiple players,
each one of them will share the same event identifier.
"""
def add_event_identifier(event),
do: Event.set_event_id(event, generate_event_uuid())

@spec generate_event_uuid ::
event_id
docp """
Returns a valid UUIDv4 used as event identifier.
"""
defp generate_event_uuid,
do: Ecto.UUID.generate()
end
Loading

0 comments on commit 124dcff

Please sign in to comment.