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

Teams Server

teams_server.livemd

Teams Server

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

require Logger

Server

defmodule UserSocket do
  @behaviour Phoenix.Socket.Transport

  @impl true
  def child_spec(_opts) do
    # We won't spawn any process, so let's ignore the child spec
    :ignore
  end

  @impl true
  def connect(%{connect_info: %{x_headers: x_headers}}) do
    org_name = get_header(x_headers, "x-org-name")
    
    Logger.debug("[SERVER] Received WebSocket connection with org name: #{org_name}")

    {:ok, %{org_name: org_name}}
  end

  @impl true
  def init(state) do
    Phoenix.PubSub.subscribe(PhoenixPlayground.PubSub, "org_events:#{state.org_name}")
    
    message = build_client_connected_message(state.org_name)
    send(self(), {:message, message})

    {:ok, state}
  end

  defp build_client_connected_message(_org_name) do
    env_var = %LivebookProto.EnvironmentVariable{name: "API_TOKEN", value: "some api token"}
    client_connected = %LivebookProto.ClientConnected{env_vars: [env_var]}
    event = %LivebookProto.Event{type: {:client_connected, client_connected}}

    LivebookProto.Event.encode(event)
  end

  @impl true
  def handle_info({:message, message}, state) do
    Logger.debug("[SERVER] Sending WebSocket message to client: #{inspect(message)}")

    {:push, {:binary, message}, state}
  end

  @impl true
  def handle_in({_message, _opts}, state) do
    {:ok, state}
  end

  @impl true
  def terminate(_reason, _state) do
    :ok
  end

  defp get_header(headers, key) do
    for {^key, value} <- headers, do: value
  end
end
defmodule Teams.Endpoint do
  use Phoenix.Endpoint, otp_app: :phoenix_playground

  socket("/user", UserSocket, websocket: [connect_info: [:x_headers]])
end
{:ok, phx_playground_pid} =
  PhoenixPlayground.start(endpoint: Teams.Endpoint, port: 4701, open_browser: false)
import Kino.Shorts

build_event = fn :env_var_created, env_var ->
  env_var = %LivebookProto.EnvironmentVariable{name: env_var.name, value: env_var.value}
  env_var_created = %LivebookProto.EnvironmentVariableCreated{env_var: env_var}
  event = %LivebookProto.Event{type: {:env_var_created, env_var_created}}

  LivebookProto.Event.encode(event)
end

feedback_frame = Kino.Frame.new(placeholder: false)

form =
  Kino.Control.form(
    [
      org_name: Kino.Input.text("Org name", default: "dashbit"),
      name: Kino.Input.text("Name"),
      value: Kino.Input.text("Value")
    ],
    submit: "Create"
  )

Kino.listen(form, fn form_event ->
  %{data: %{org_name: org_name, name: name, value: value}} = form_event
  Kino.Frame.render(feedback_frame, Kino.Text.new("env var created", style: [color: :green]))

  message = build_event.(:env_var_created, %{name: name, value: value})

  Phoenix.PubSub.broadcast!(
    PhoenixPlayground.PubSub,
    "org_events:#{org_name}",
    {:message, message}
  )
end)

grid([markdown("### New env var"), feedback_frame, form], boxed: true)