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

Commit 87fc355

Browse files
author
Marcelo Amancio de Lima Santos
committed
WIP
1 parent 22b18a4 commit 87fc355

File tree

22 files changed

+497
-51
lines changed

22 files changed

+497
-51
lines changed

lib/account/websocket/channel/account.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ channel Helix.Account.Websocket.Channel.Account do
1414
alias Helix.Network.Websocket.Requests.Bounce.Remove, as: BounceRemoveRequest
1515
alias Helix.Software.Websocket.Requests.Virus.Collect, as: VirusCollectRequest
1616
alias Helix.Story.Websocket.Requests.Email.Reply, as: EmailReplyRequest
17-
alias Helix.Universe.Websocket.Channel.Requests.CreateAccount,
17+
alias Helix.Universe.Bank.Websocket.Requests.CreateAccount,
1818
as: BankAccountCreateRequest
1919

2020
@doc """

lib/core/validator/validator.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ defmodule Helix.Core.Validator do
55
| :hostname
66
| :bounce_name
77
| :reply_id
8+
| :token
89

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

lib/event/notificable/notificable.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ defprotocol Helix.Event.Notificable do
6363
action, also receive special treatment. Hence:
6464
6565
- third AT attack_target - Third party on victim's server
66-
- third AT attack_source - Third party on attacker's server.
66+
- third AT attack_source - Third party on attacker's server.
6767
- third AT random_server - Third party on unrelated (random) server.
6868
6969
Last but not least, in some cases we do not have an attacker/victim
@@ -98,11 +98,14 @@ defprotocol Helix.Event.Notificable do
9898

9999
alias Helix.Account.Model.Account
100100
alias Helix.Server.Model.Server
101+
alias Helix.Universe.Bank.Model.ATM
102+
alias Helix.Universe.Bank.Model.BankAccount
101103

102104
@type whom_to_notify ::
103105
%{
104106
optional(:server) => [Server.id],
105-
optional(:account) => [Account.id]
107+
optional(:account) => [Account.id],
108+
optional(:bank_account) => [{ATM.id, BankAccount.account}]
106109
}
107110

108111
@spec generate_payload(event :: struct, Socket.t) ::

lib/event/notification_handler.ex

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ defmodule Helix.Event.NotificationHandler do
88
alias Helix.Entity.Model.Entity
99
alias Helix.Server.Model.Server
1010
alias Helix.Server.State.Websocket.Channel, as: ServerWebsocketChannelState
11+
alias Helix.Universe.Bank.Model.ATM
12+
alias Helix.Universe.Bank.Model.BankAccount
1113

1214
@type channel_account_id :: Account.id | Entity.id
15+
@type channel_bank_account_id :: {ATM.id, BankAccount.account}
1316

1417
@doc """
1518
Handler responsible for guiding the event through the Notificable flow. It
@@ -51,13 +54,25 @@ defmodule Helix.Event.NotificationHandler do
5154
accounts
5255
|> Utils.ensure_list()
5356
|> Enum.uniq()
54-
|> get_account_channels()
57+
|> get_bank_account_channels()
5558
|> List.flatten()
5659
|> Kernel.++(acc)
5760

5861
channel_mapper(Map.delete(notify, :account), acc)
5962
end
6063

64+
defp channel_mapper(notify = %{bank_account: bank_accs}, acc) do
65+
acc =
66+
bank_accs
67+
|> Utils.ensure_list()
68+
|> Enum.uniq()
69+
|> get_bank_account_channels()
70+
|> List.flatten()
71+
|> Kernel.++(acc)
72+
73+
channel_mapper(Map.delete(notify, :bank_account), acc)
74+
end
75+
6176
defp channel_mapper(%{}, acc),
6277
do: acc
6378

@@ -94,6 +109,15 @@ defmodule Helix.Event.NotificationHandler do
94109
defp get_account_channels(account_id),
95110
do: ["account:" <> to_string(account_id)]
96111

112+
@spec get_bank_account_channels(
113+
[channel_bank_account_id] | channel_bank_account_id
114+
) ::
115+
channels :: [String.t]
116+
defp get_bank_account_channels(bank_accounts),
117+
do: Enum.map(bank_accounts, &get_bank_account_channels/1)
118+
defp get_bank_account_channels({atm_id, acc_num}),
119+
do: ["bank:" <> to_string(atm_id) <> to_string(acc_num)]
120+
97121
defp concat(a, b),
98122
do: a <> to_string(b)
99123
end

lib/universe/bank/action/bank.ex

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ defmodule Helix.Universe.Bank.Action.Bank do
2727
as: BankAccountPasswordChangedEvent
2828
alias Helix.Universe.Bank.Event.Bank.Account.Token.Acquired,
2929
as: BankAccountTokenAcquiredEvent
30+
alias Helix.Universe.Bank.Event.Bank.Account.Removed,
31+
as: BankAccountRemovedEvent
32+
alias Helix.Universe.Bank.Event.Bank.Transfer.Successful,
33+
as: BankTransferSuccessfulEvent
34+
alias Helix.Universe.Bank.Event.Bank.Transfer.Failed,
35+
as: BankTransferFailedEvent
3036

3137
@spec start_transfer(BankAccount.t, BankAccount.t, pos_integer, Account.idt) ::
3238
{:ok, BankTransfer.t}
@@ -51,9 +57,8 @@ defmodule Helix.Universe.Bank.Action.Bank do
5157
as: :start
5258

5359
@spec complete_transfer(BankTransfer.t) ::
54-
:ok
55-
| {:error, {:transfer, :notfound}}
56-
| {:error, :internal}
60+
{:ok, BankTransfer.t, [BankTransferSuccessfulEvent.t]}
61+
| {:error, BankTransfer.t, [BankTransferFailedEvent.t]}
5762
@doc """
5863
Completes the transfer.
5964
@@ -66,9 +71,19 @@ defmodule Helix.Universe.Bank.Action.Bank do
6671
This function should not be called directly by Public. Instead, it must be
6772
triggered by the BankTransferCompletedEvent.
6873
"""
69-
defdelegate complete_transfer(transfer),
70-
to: BankTransferInternal,
71-
as: :complete
74+
def complete_transfer(transfer) do
75+
case BankTransferInternal.complete(transfer) do
76+
:ok ->
77+
{:ok, transfer, [BankTransferSuccessfulEvent.new(transfer.transfer_id)]}
78+
79+
{:error, reason} ->
80+
{
81+
:error,
82+
transfer,
83+
[BankTransferFailedEvent.new(transfer.transfer_id, reason)]
84+
}
85+
end
86+
end
7287

7388
@spec abort_transfer(BankTransfer.t) ::
7489
:ok
@@ -91,7 +106,7 @@ defmodule Helix.Universe.Bank.Action.Bank do
91106
as: :abort
92107

93108
@spec open_account(Account.idt, ATM.id) ::
94-
{:ok, BankAccount.t}
109+
{:ok, BankAccount.t, [BankAccountUpdatedEvent.t]}
95110
| {:error, Ecto.Changeset.t}
96111
@doc """
97112
Opens a bank account.
@@ -103,23 +118,34 @@ defmodule Helix.Universe.Bank.Action.Bank do
103118
|> Map.get(:entity_id)
104119
|> NPCQuery.fetch()
105120

106-
%{owner_id: owner, atm_id: atm, bank_id: bank}
107-
|> BankAccountInternal.create()
121+
case BankAccountInternal.create(owner, atm, bank) do
122+
{:ok, bank_acc} ->
123+
{:ok, bank_acc, [BankAccountUpdatedEvent.new(bank_acc, :created)]}
124+
125+
error ->
126+
error
127+
end
108128
end
109129

110130
@spec close_account(BankAccount.t) ::
111131
:ok
112-
| {:error, {:account, :notfound}}
113-
| {:error, {:account, :notempty}}
132+
| {:error, {:bank_account, :not_found}}
133+
| {:error, {:bank_account, :not_empty}}
114134
@doc """
115135
Closes a bank account.
116136
117137
May fail if the account is invalid or not empty. In order to close an account,
118138
its balance must be empty.
119139
"""
120-
defdelegate close_account(account),
121-
to: BankAccountInternal,
122-
as: :close
140+
def close_account(account) do
141+
case BankAccountInternal.close(account) do
142+
:ok ->
143+
{:ok, [BankAccountRemovedEvent.new(account)]}
144+
145+
{:error, reason} ->
146+
{:error, reason}
147+
end
148+
end
123149

124150
@spec direct_deposit(BankAccount.t, BankAccount.amount) ::
125151
{:ok, BankAccount.t, [BankAccountUpdatedEvent.t]}

lib/universe/bank/action/flow/bank_account.ex

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ defmodule Helix.Universe.Bank.Action.Flow.BankAccount do
55
alias Helix.Event
66
alias Helix.Entity.Query.Entity, as: EntityQuery
77
alias Helix.Network.Action.Flow.Tunnel, as: TunnelFlow
8-
alias Helix.Network.Model.Connection
98
alias Helix.Network.Query.Network, as: NetworkQuery
109
alias Helix.Process.Model.Process
1110
alias Helix.Server.Model.Server
@@ -61,13 +60,32 @@ defmodule Helix.Universe.Bank.Action.Flow.BankAccount do
6160
Opens a new BankAccount to given Account.id
6261
"""
6362
def open(account_id, atm_id) do
64-
bank_account =
65-
BankAction.open_account(account_id, atm_id)
66-
case bank_account do
67-
{:ok, bank_account} ->
68-
{:ok, bank_account}
69-
{:error, _} ->
70-
{:error, :internal}
63+
flowing do
64+
with \
65+
{:ok, bank_acc, events} <- BankAction.open_account(account_id, atm_id),
66+
on_success(fn -> Event.emit(events) end)
67+
do
68+
{:ok, bank_acc}
69+
else
70+
_ ->
71+
{:error, :internal}
72+
end
73+
end
74+
end
75+
76+
@spec close(BankAccount.t) ::
77+
:ok
78+
| {:error, {:bank_account, :not_found}}
79+
| {:error, {:bank_account, :not_empty}}
80+
def close(bank_account) do
81+
flowing do
82+
with \
83+
true <- not is_nil(bank_account),
84+
{:ok, events} <- BankAction.close_account(bank_account),
85+
on_success(fn -> Event.emit(events) end)
86+
do
87+
:ok
88+
end
7189
end
7290
end
7391

lib/universe/bank/event/bank/account.ex

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,47 @@ defmodule Helix.Universe.Bank.Event.Bank.Account do
22

33
import Helix.Event
44

5+
event Removed do
6+
7+
alias Helix.Universe.Bank.Model.BankAccount
8+
9+
event_struct [:account]
10+
11+
@type t ::
12+
%__MODULE__{
13+
account: BankAccount.t
14+
}
15+
16+
@spec new(BankAccount.t) ::
17+
t
18+
19+
def new(account = %BankAccount{}) do
20+
%__MODULE__{
21+
account: account
22+
}
23+
end
24+
25+
notify do
26+
27+
@event :bank_account_removed
28+
29+
@doc false
30+
def generate_payload(event, _socket) do
31+
data =
32+
%{
33+
atm_id: to_string(event.account.atm_id),
34+
account_number: event.account.account_number
35+
}
36+
37+
{:ok, data}
38+
end
39+
40+
@doc false
41+
def whom_to_notify(event),
42+
do: %{account: event.account.owner_id}
43+
end
44+
end
45+
546
event Updated do
647
@moduledoc """
748
`BankAccountUpdatedEvent` is fired when the underlying bank account has
@@ -19,7 +60,7 @@ defmodule Helix.Universe.Bank.Event.Bank.Account do
1960
reason: reason
2061
}
2162

22-
@type reason :: :balance | :password
63+
@type reason :: :balance | :password | :created
2364

2465
@spec new(BankAccount.t, reason) ::
2566
t
@@ -81,5 +122,77 @@ defmodule Helix.Universe.Bank.Event.Bank.Account do
81122
token_id: token_id
82123
}
83124
end
125+
126+
notify do
127+
@moduledoc """
128+
Notifies the client of bank account login, so it can properly update
129+
the local data.
130+
"""
131+
132+
@event :bank_login_event
133+
134+
@doc false
135+
def generate_payload(event, _socket) do
136+
data =
137+
%{
138+
atm_id: to_string(event.account.atm_id),
139+
account_number: event.account.account_number,
140+
balance: event.account.balance,
141+
password: event.account.password
142+
}
143+
144+
{:ok, data}
145+
end
146+
147+
def whom_to_notify(event) do
148+
atm_id = event.account.atm_id
149+
account_number = event.account.account_number
150+
151+
%{
152+
account: event.entity_id,
153+
bank_account: {atm_id, account_number}
154+
}
155+
end
156+
end
157+
end
158+
159+
event Logout do
160+
161+
alias Helix.Entity.Model.Entity
162+
alias Helix.Universe.Bank.Model.BankAccount
163+
164+
event_struct [:account, :entity_id]
165+
166+
@type t :: %__MODULE__{
167+
account: BankAccount.t,
168+
entity_id: Entity.id
169+
}
170+
171+
@spec new(BankAccount.t, Entity.id) ::
172+
t
173+
def new(account = %BankAccount{}, entity_id = %Entity.ID{}) do
174+
%__MODULE__{
175+
account: account,
176+
entity_id: entity_id
177+
}
178+
end
179+
180+
notify do
181+
182+
@event :bank_logout_event
183+
184+
def generate_payload(event, _socket) do
185+
data =
186+
%{
187+
atm_id: to_string(event.account.atm_id),
188+
account_number: event.account.account_number
189+
}
190+
191+
{:ok, data}
192+
end
193+
194+
def whom_to_notify(event),
195+
do: %{account: event.entity_id}
196+
end
84197
end
85198
end

0 commit comments

Comments
 (0)