architex/lib/architex_web/client/controllers/sync_controller.ex

74 lines
2.2 KiB
Elixir

defmodule ArchitexWeb.Client.SyncController do
use ArchitexWeb, :controller
import ArchitexWeb.Error
import Ecto.Query
alias Architex.{Repo, Event, Account, Room, Membership}
alias Plug.Conn
@doc """
Synchronise the client's state with the latest state on the server.
Parameters: %{"filter" => "{\"account_data\":{},\"presence\":{},\"room\":{\"account_data\":{},\"ephemeral\":{},\"state\":{\"lazy_load_members\":true},\"timeline\":{\"limit\":100}}}", "path" => ["_matrix", "client", "r0", "sync"], "timeout" => "30000"}
Action for GET /_matrix/client/r0/sync.
"""
# When no "since" is specified, return the most recent messages.
def sync(%Conn{assigns: %{account: %Account{id: account_id}}} = conn, params)
when not is_map_key(params, "since") do
# joined_rooms =
# account
# |> Ecto.assoc(:joined_rooms)
# |> Repo.all()
# |> Enum.into(%{}, fn %Room{id: room_id} = room ->
# {room_id, room}
# end)
events_per_room =
Event
|> join(:inner, [e], m in Membership,
on: m.room_id == e.room_id and m.account_id == ^account_id and m.membership == "join"
)
|> join(:inner, [e, m], r in Room, on: r.id == m.room_id)
|> order_by(asc: :origin_server_ts, asc: :nid)
|> Repo.all()
|> Enum.group_by(& &1.room_id)
join =
Enum.into(events_per_room, %{}, fn {room_id, [%Event{nid: first_nid} | _] = events} ->
joined_room = %{
timeline: %{
events: Enum.map(events, &Event.Formatters.sync_response/1),
limited: false,
prev_batch: Integer.to_string(first_nid)
}
}
{room_id, joined_room}
end)
next_batch =
Enum.map(events_per_room, fn {_, events} ->
%Event{nid: last_nid} = List.last(events)
last_nid
end)
|> Enum.max(fn -> 0 end)
data = %{
next_batch: Integer.to_string(next_batch),
rooms: %{
join: join,
invite: %{},
leave: %{}
}
}
conn
|> put_status(200)
|> json(data)
end
# TODO: Long-poll for new incoming events.
# Should think about how to implement this in a nice way.
def sync(conn, _params), do: put_error(conn, :unknown, "Not implemented yet.")
end