CrowdHailer / raxx

Interface for HTTP webservers, frameworks and clients
https://hexdocs.pm/raxx
Apache License 2.0
402 stars 29 forks source link

Unified streaming solution. #47

Closed CrowdHailer closed 7 years ago

CrowdHailer commented 7 years ago

This pull request is required to make Raxx more friendly to HTTP/2. This has meant the deprecation of certain features around transfer-encoding and old solutions on streaming. The result is raxx applications will implement several callbacks, rather than a single handle_request.

Given a chat application with three endpoints, each can be a simple Raxx.App

For the home_page.ex a simple Request with no body is reacted too with a single response with the body generated all at once.

defmodule HomePage do
  use Raxx.App

  require EEx

  EEx.function_from_file(:defp, :home_page, Path.join(__DIR__, "./templates/home_page.html.eex"), [])

  def handle_headers(request, config) do
    body = home_page()
    Raxx.Response.new(:ok, [{"content-type", "text/html"}], body)
  end
end

For publish_message.ex a post endpoint where the body is read into a complete buffer

defmodule PublishMessage do
  use Raxx.App

  alias WaterCooler.ChatRoom
  require ChatRoom

  def handle_headers(request, config) do
    {[], {:reading, ""}}
  end

  def handle_fragment(fragment, {:reading, buffer}) do
    {[], {:reading, buffer <> fragment}}
  end

  def handle_trailers([], {:reading, body}) do
    {:ok, %{message: message}} = parse_publish_form(body)
    {:ok, _} = ChatRoom.publish(message)
    response = Raxx.Response.new(303, [{"location", "/"}], false)
  end

  def parse_publish_form(raw) do
    %{"message" => message} = URI.decode_www_form(raw) |> URI.decode_query
    {:ok, %{message: message}}
  end

end

A subscribe_to_messages.ex endpoint where the server can push information.

defmodule SubscribeToMessages do
  use Raxx.App

  alias WaterCooler.ChatRoom
  require ChatRoom

  def handle_headers(request, config) do
    {:ok, _} = ChatRoom.join()
    response = Raxx.Response.new(:ok, [{"content-type", "text/event-stream"}], true)
    response
  end
end

Questions

def PublishMessage do
  use Raxx.Unary, max_buffer: 1_000_000 # limit to body read from socket 

  def handle_request(request, config) do
    {:ok, %{message: message}} = parse_publish_form(request.body)
    {:ok, _} = ChatRoom.publish(message)
    Raxx.Response.new(303, [{"location", "/"}], false)
  end
end