Current section

Files

Jump to
eddb lib user UserServer.ex
Raw

lib/user/UserServer.ex

defmodule User.UserServer do
require Logger
alias User.User
alias Utilities.Serialize
import Serialize
use GenServer, restart: :permanent
@storage "users.json"
def init(init_arg) do
{:ok, init_arg}
end
def start_link(_) do
state =
if File.exists?(@storage) do
retrieve_object(@storage)
else
[]
end
IO.inspect(state)
GenServer.start_link(__MODULE__, state, name: :user_server)
end
def handle_call({:create_user, %User{} = user}, _caller_pid, state) do
username_taken =
state
|> Enum.filter(&(&1.username == user.username))
|> Enum.any?()
# Check if username is alreay taken and password is long enough.
# Create user and append to state if conditions are meet
cond do
username_taken ->
Logger.error("Username #{user.username} is alreay taken")
{:reply, nil, state}
String.length(user.password) < 8 ->
Logger.error("Password is to short")
{:reply, nil, state}
true ->
Logger.info("User #{user.username} created")
state = [user | state]
store_object(@storage, state)
{:reply, user, state}
end
end
def handle_call({:auth_user, username, password}, _caller_pid, state) do
user =
state
|> Enum.find(&User.is_valid?(&1, username, password))
# Check if user is authenticated (exsits)
# Return false if not
case user do
nil ->
Logger.error("Failed authentication: #{username}")
{:reply, nil, state}
user ->
{:reply, user, state}
end
end
def create_user(username, password, permission) do
user = User.new(username, password, permission)
callback = fn {pid, user} ->
pid
|> GenServer.call({:create_user, user})
end
# Create user local
callback.({Process.whereis(:user_server), user})
# Replicate data on other nodes
Node.list()
|> Enum.each(fn node ->
pid = :rpc.call(node, Process, :whereis, [:user_server])
callback.({pid, user})
end)
end
@doc """
Check if user credentials are valid
"""
def auth_user(username, password) when is_binary(username) and is_binary(password) do
# Search locally
# callback returns either nil or the User
callback = fn {pid, username, password} ->
pid
|> GenServer.call({:auth_user, username, password})
end
case callback.({Process.whereis(:user_server), username, password}) do
# Search on other nodes as this node does not contain the data
nil ->
Node.list()
|> Enum.find(fn node ->
pid = :rpc.call(node, Process, :whereis, [:user_server])
callback.({pid, username, password})
end)
# Simply return the user
user ->
user
end
end
end