Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Teams Client

talks/alchemyconf/teams_client.livemd

Teams Client

Mix.install([
  {:phoenix_playground, "~> 0.1.7"},
  {:livebook_proto,
   github: "hugobarauna/livebook-notebooks", sparse: "talks/alchemyconf/livebook_proto"},
  {:websockex, "~> 0.5.0", hex: :websockex_wt},
  {:kino, "~> 0.15.3"}
])

require Logger

Client

defmodule Teams.Connection do
  use WebSockex

  @loop_ping_delay 5_000
  @teams_ws_url "http://localhost:4701/user/websocket"

  def start_link(listener, headers, url \\ @teams_ws_url) do
    WebSockex.start_link(url, __MODULE__, %{listener: listener}, extra_headers: headers)
  end

  def handle_connect(_conn, state) do
    send(state.listener, {:connection_state, :connected})
    Process.send_after(self(), :loop_ping, @loop_ping_delay)
    {:ok, state}
  end

  def handle_frame({:binary, msg}, state) do
    Logger.debug("[CLIENT] Received WebSocket binary message: #{inspect(msg)}")

    event = LivebookProto.Event.decode(msg)
    Logger.debug("[CLIENT] Decoded WebSocket binary message: #{inspect(event)}")

    %{type: {type, message}} = event
    send(state.listener, {:event, type, message})

    {:ok, state}
  end

  def handle_frame({type, msg}, state) do
    IO.puts("Received Message - Type: #{inspect(type)} -- Message: #{inspect(msg)}")
    {:ok, state}
  end

  def handle_info(:loop_ping, state) do
    Process.send_after(self(), :loop_ping, @loop_ping_delay)
    {:reply, :ping, state}
  end
end
defmodule Teams.Client do
  use GenServer

  defstruct [
    :org_name,
    :env_vars,
    :connection_pid,
    connection_state: :disconnected
  ]

  def start_link(org_name) do
    GenServer.start_link(__MODULE__, org_name, name: __MODULE__)
  end

  def get_environment_variables() do
    GenServer.call(__MODULE__, :get_environment_variables)
  end

  @impl true
  def init(org_name) do
    headers = [{"x-org-name", org_name}]
    {:ok, connection_pid} = Teams.Connection.start_link(self(), headers)
    {:ok, %__MODULE__{org_name: org_name, connection_pid: connection_pid}}
  end

  @impl true
  def handle_info({:connection_state, :connected}, state) do
    {:noreply, %{state | connection_state: :connected}}
  end

  @impl true
  def handle_info({:event, :client_connected, %LivebookProto.ClientConnected{} = message}, state) do
    %LivebookProto.ClientConnected{env_vars: env_vars} = message

    env_vars =
      for env_var <- env_vars do
        %{name: env_var.name, value: env_var.value}
      end

    {:noreply, %{state | env_vars: env_vars}}
  end

  @impl true
  def handle_info(
        {:event, :env_var_created, %LivebookProto.EnvironmentVariableCreated{} = message},
        state
      ) do
    %LivebookProto.EnvironmentVariableCreated{env_var: env_var} = message

    env_var = %{name: env_var.name, value: env_var.value}

    Phoenix.PubSub.broadcast!(
      PhoenixPlayground.PubSub,
      "org_events:#{state.org_name}",
      {:env_var_created, env_var}
    )

    env_vars = [env_var | state.env_vars]
    {:noreply, %{state | env_vars: env_vars}}
  end

  @impl true
  def handle_call(:get_environment_variables, _from, state) do
    {:reply, state.env_vars, state}
  end
end
teams_client = Kino.start_child!({Teams.Client, "dashbit"})
Kino.nothing()
defmodule Teams.OrgLive do
  use Phoenix.LiveView

  def mount(_params, _session, socket) do
    org_name = "dashbit"
    Phoenix.PubSub.subscribe(PhoenixPlayground.PubSub, "org_events:#{org_name}")

    socket =
      assign(socket, org_name: org_name, env_vars: Teams.Client.get_environment_variables())

    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    

Org: <%= @org_name %>

Environment Variables

<%= for env_var <- @env_vars do %> <% end %>
Name Value
<%= env_var.name %> <%= env_var.value %>
"""
end def handle_info({:env_var_created, env_var}, socket) do {:noreply, update(socket, :env_vars, fn env_vars -> [env_var | env_vars] end)} end end
{:ok, phx_playground_pid} =
  PhoenixPlayground.start(live: Teams.OrgLive, port: 4700)