GenericJam

GenericJam

Working config for gun websocket client

Just leaving some breadcrumbs for future me and future others like me.

Connect with TCP (not secured) - most servers will reject but useful for localhost, etc.

connect_opts =
      %{
        connect_timeout: 60000,
        retry: 10,
        retry_timeout: 300,
        transport: :tcp,
        # Specify :http or :http2 to tell the server what you'd like. Support for http 2  is not great generally
        protocols: [:http],
        # Tell the server which version to use. Note: this is an atom.
        http_opts: %{version: :"HTTP/1.1"}
      }

Connect with TLS/SSH but you don’t care to verify the host

connect_opts,
    do:
      %{
        connect_timeout: 60000,
        retry: 10,
        retry_timeout: 300,
        transport: :tls,
        tls_opts: [
          verify: :verify_none,
          # Specify a bunch of certs
          cacerts: :certifi.cacerts(),
          # Or just one cert
          # cacertfile: CAStore.file_path(),
          depth: 99,
          reuse_sessions: false
        ],
        # See above explanation why you should specify
        http_opts: %{version: :"HTTP/1.1"},
        protocols: [:http],
      }

Using TLS/SSH and you want to verify the host

connect_opts = %{
        connect_timeout: 60000,
        retry: 10,
        retry_timeout: 300,
        transport: :tls,
        tls_opts: [
          verify: :verify_peer,
          cacerts: :certifi.cacerts(),
          # cacertfile: CAStore.file_path(),
          depth: 99,
          server_name_indication: 'example.com',
          reuse_sessions: false,
          verify_fun: {&:ssl_verify_hostname.verify_fun/3, [check_hostname: 'example.com']}
        ],
        http_opts: %{version: :"HTTP/1.1"},
        protocols: [:http]
      }

For :certifi and CAStore you may need to install these libs if they are not already in use in your project.

Use like

{:ok, gun_pid} = :gun.open('ws.example.com', 443, connect_opts)
# Wait for gun to be up - equivalent to :gun_up message
{:ok, http_version} = :gun.await_up(gun_pid)
# Put gun_pid and stream_ref in state to match on incoming messages
stream_ref = :gun.ws_upgrade(gun_pid, path(), headers()) |> IO.inspect()

Elsewhere monitor for the upgrade message. If you’re using a GenServer this will land in handle_info.

def handle_info({:gun_upgrade, gun_pid, stream_ref, stuff, headers}, %{gun_pid: gun_pid, stream_ref: stream_ref} = state) do
  # Now the websocket is upgraded and can send and receive
  :gun.ws_send(gun_pid, stream_ref, {:text, "Hello Server"})
  {:noreply, state}
end 

If you’re using a GenServer the rest of the messages from gun will land in other handle_infos so make a clause for each one you want to handle.

This should also work for libs that use gun such as glock.

First Post!

stevensonmt

stevensonmt

Have you thought about putting together a tiny library for this that just provides a couple functions for creating sane connect_opts for the couple of different scenarios you’ve listed? Might be more readily discoverable via Hex than this forum post in the long run.

Most Liked

GenericJam

GenericJam

There’s already glock which I was going to do a PR for. I might do that.

I was also thinking about doing my own take on it but those ideas are still percolating.

I was trying to use glock but then I was getting a bit frustrated with why it wasn’t working so I just resorted to gun which is actually fine once you know what it’s doing. I would want whatever lib I made to be more useful than just making :gun into Gun.

For example I’m not sure it’s actually beneficial obscuring the websocket upgrade as that is kind of important. That’s part of what I like about gun is it gives you access to the guts of what’s happening and gives you the option to react to it.

I’m thinking whatever lib I’d make would be paired with the user’s genserver and report back each of the stages.

GenericJam

GenericJam

I made a PR for glock. Hopefully it will be merged soon.

Where Next?

Popular in Guides/Tuts Top

smpallen99
Did you know that IO.inspect/2 returns the the first argument and accepts a label option as a second argument. This makes it a perfect to...
New
njwest
Greetings: I just wrote a step-by-step guide on building a Phoenix 1.3 JWT Auth API with Guardian JWTs and Comeonin password hashing. I ...
New
berts-4865
Here is a quick guide to uploading a file from the browser to DO spaces. It is crude, but will hopefully save sometime time and frustrat...
New
kevinlang
Hey all, With Phoenix 1.6 just around the corner, I figured I’d make a tutorial on how to add Bulma to a new Phoenix 1.6 project. By lev...
New
hauks96
Hello everyone, I created a deployment tutorial for Phoenix applications with Kubernetes (microk8s) a few months back with the goal of s...
New
Jskalc
Sorry if it’s a common knowledge, but it’s something I just learned and wanted to share. I’ve seen that mind-blowing demo of hot-reload ...
New
rhcarvalho
After collecting information from multiple sources (this forum, blogs, StackOverflow and GitHub), I was finally able to successfully embe...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

We're in Beta

About us Mission Statement