DmitriyChernyavskiy
Hello everyone,
I’m a new in elexir and functional language. I’m trying to implement Websocket interraction with server.
On first layer I implement module based on GenServer with functionality like WebSockex and use ninenines/gun as Websocket client. This module name egun, below are the code snippets:
defmodule Egun do
use GenServer
@callback handle_connect(state :: term) :: {:ok, new_state :: term}
@callback handle_message(msg :: term, state :: term) :: {:ok, new_state} | ...
@callback handle_send(msg :: term, state :: term) :: {:ok, new_state} | ...
...
defmacro __using__(_opts) do
quote location: :keep do
@behaviour Egun
@doc false
def handle_connect(state) do
{:ok, state}
end
@doc false
def handle_message(message, _state) do
raise "No handle_message/2 clause in #{__MODULE__} provided for #{inspect(message)}"
end
@doc false
def handle_send(message, state) do
{:reply, {:text, message}, state}
end
defoverridable handle_connect: 1,
handle_message: 2,
handle_send: 2
end
def start_link(conn = %Conn{}) do
GenServer.start_link(__MODULE__, %__MODULE__{
conn: conn,
})
end
def init(state) do
...
send(self(), :ws_connected)
{:ok, state}
end
def send_message(client, message) do
GenServer.call(client, {:ws_syncsend, message})
end
def handle_call({:ws_syncsend, message}, sender, state) do
message = compose_msg(message, state.conn)
...
{:reply, message, state}
end
def handle_info(:ws_connected, state) do
common_handle(:handle_connect, state)
end
def handle_info(
{:gun_ws, _gun_pid, _ws_stream, {:text, message}}, state
) do
case Jason.decode(message, keys: :atoms) do
{:ok, msg} ->
common_handle({:handle_message, msg}, state)
error ->
{:stop, error, state}
end
end
defp common_handle({function, msg}, state) when is_atom(function) do
result = apply(state.module, function, [msg, state])
common_handle_ret(result, {function, msg}, state)
end
defp common_handle(function, state) when is_atom(function) do
result = apply(state.module, function, [state])
common_handle_ret(result, {function, nil}, state)
end
defp common_handle_ret(result, {function, msg}, state) do
case result do
{:ok, new_state} ->
{:noreply, new_state}
{:reply, frame, new_state} ->
:gun.ws_send(new_state.gun_pid, frame_encode(frame))
{:noreply, new_state}
....
end
end
This implementation provides messaging through an open Websocket. Next I need extend functionality egun. And create module session which adds business logic methods:
defmodule Session do
@moduledoc nil
use Egun
def create(client) when is_pid(client) do
tr = Egun.send_message(client, %{
session: "create",
transaction: "yes"
})
GenServer.call(client, {:push_transaction, tr, client})
end
@impl true
def handle_call({:push_transaction, transaction, callback_pid}, _from, state) do
trs = Map.put(state.transactions, transaction, callback_pid)
{:noreply, %{state | transactions: trs}}
end
@impl Egun
def handle_message(message, state) do
IO.puts("Handle message: #{inspect(message)}")
IO.puts("State: #{inspect(state)}")
{:ok, state}
end
end
After compile I get warning message:
warning: got "@impl Egun" for function handle_call/3 but this behaviour does not specify such callback. The known callbacks are:
* Egun.handle_connect/1 (function)
* Egun.handle_message/2 (function)
* Egun.handle_send/2 (function)
How can I modify my modules so that the Session module can implement the behavior of the GenServer and Egan without using an additional GenServer. On object oriented programming language Session can get access to all methods from GenServer and Egan?
Trending in Challenges
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 7- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
al2o3cr
Couple things:
...ed something important, because@impldoesn’t appear anywhere in the posted codedefoverridablewhich sounds very OO, but is slightly differentDmitriyChernyavskiy
Thanks for your reply. I added parts of the code that I missed. I known elixir not “OO” language. I only use “OO” terminology.
kokolegorille
… and techniques, which does not suit FP.
You don’t use inheritance, but composition in FP.
ycherniavskyi
Maybe you could suggest some good books or posts about migration from OO to FP paradigm
?
kokolegorille
Yes I can.
This video (and all videos made by Scott Wlaschin)
I cannot tell You how much impact they had on me
Laetitia
Very good video!
Thanks for sharing
Exadra37
For me, the only thing that made the click to switch the brain from OOP to FP was the book:
and the video course:
@pragdave spends a great deal of time in both the book and in the video course to get you into the FP mode of thinking, thus I cannot recommend enough that you chose the book or the video to get you in the mindset of FP