A websocket client that uses websocat via a Port.
In case of a crash of websocat
it will be restarted and submit the same commands as before to get back to the state before the crash.
If
iex> System.find_executable("websocat")
returns a valid path you are good to go!
def deps do
[
{:ws_client, "~> 0.1.0"}
]
end
# create callback on how to handle the received data from the server
cb = fn data -> data |> IO.inspect end
# the server to connect to
url = "wss://echo.websocket.org"
# start the worker (GenServer)
{:ok, _} =
GenServer.start_link(WsClient.Worker, %{cb: cb, url: url, port: "", commands: []}, name: EchoWorker)
# send from the client to the server, the callback defined above will handle the answer message.
WsClient.send(TestWorker, "hi\n")
def start(_type, _args) do
children = [
{WsClient.Worker,
args: %{
cb: &IO.inspect/1,
url: "wss://echo.websocket.org",
port: "",
commands: []
},
name: EchoWorker}
]
opts = [strategy: :one_for_one, name: Test.Supervisor]
Supervisor.start_link(children, opts)
end
This may be useful in case you want to connect to multiple websocket endpoints at the same time.
@impl true
def start(_type, _args) do
children = [
Supervisor.child_spec(
{WsClient.Worker,
args: %{
cb: &IO.inspect/1,
url: "wss://echo.websocket.org",
port: "",
commands: []
},
name: FirstWorker},
id: :my_worker_1
),
Supervisor.child_spec(
{WsClient.Worker,
args: %{
cb: &IO.inspect/1,
url: "wss://echo.websocket.org",
port: "",
commands: []
},
name: SecondWorker},
id: :my_worker_2
)
]
opts = [strategy: :one_for_one, name: Test.Supervisor]
Supervisor.start_link(children, opts)
end
After the connection you can use
WsClient.send(pid, message)
to send a message to the web server you are connected to, e.g.
WsClient.send(TestWorker, "hi\n")
To change the handling callback at runtime use
WsClient.callback(pid, fun)
Example with Elixir 1.18 and the new internal JSON function:
cb = fn data -> JSON.decode(data) end
WsClient.callback(Worker, cb)
To close the port (will otherwise be handled automatically on exit of the GenServer)
WsClient.disconnect(pid)