Files
comp4958/lectures/03/lec3.ex
T

77 lines
1.6 KiB
Elixir

# how to implement a generic server
# motivation for GenServer
defmodule GenericServer do
### Server Implementation ###
# pass in a module 'm', since module names are just atoms
# more generic, take in starting args and pass to modules
# init function to do whatever is required beforehand
def start(m, arg) do
state = m.init(arg)
spawn(fn -> loop(m, state) end)
end
defp loop(m, state) do
receive do
{:call, msg, from} ->
{reply, new_state} = m.handle_call(msg, from, state)
send(from, {self(), reply})
loop(m, new_state)
{:cast, msg} ->
new_state = m.handle_cast(msg, state)
loop(m, new_state)
end
end
### Client API ###
def call(pid, msg, timeout \\ 5000) do
send(pid, {:call, msg, self()})
receive do
# pin operator, reply must have same pid as call argument pid
{^pid, x} -> x
after
timeout ->
:timeout
end
end
def cast(pid, msg) do
send(pid, {:cast, msg})
end
end
defmodule Counter do
### Server Implementation ###
def start(file) do
GenericServer.start(__MODULE__, file)
end
def init(file) do
with {:ok, content} <- File.read(file),
{n, _} <- Integer.parse(content) do
n
end
if is_integer(val), do: val, else: 0
end
def handle_call(:value, _from, state) do
# -> {reply, new_state} in GenericServer
{state, state}
end
def handle_cast({:inc, amt}, state) do
state + amt
end
### Client API ###
def value(pid) do
GenericServer.call(pid, :value)
end
def inc(pid, amt \\ 1) do
GenericServer.cast(pid, {:inc, amt})
end
end