Add initial implementatin of client /sync endpoint without 'since'
parameter
This commit is contained in:
parent
5f0fd7fabe
commit
7a1bf01869
7 changed files with 121 additions and 12 deletions
|
@ -4,8 +4,8 @@ defmodule Architex.Event.Formatters do
|
|||
"""
|
||||
alias Architex.Event
|
||||
|
||||
@spec for_client(Event.t()) :: map()
|
||||
def for_client(%Event{
|
||||
@spec messages_response(Event.t()) :: map()
|
||||
def messages_response(%Event{
|
||||
content: content,
|
||||
type: type,
|
||||
id: event_id,
|
||||
|
@ -30,6 +30,27 @@ defmodule Architex.Event.Formatters do
|
|||
data
|
||||
end
|
||||
|
||||
def sync_response(%Event{
|
||||
content: content,
|
||||
type: type,
|
||||
id: event_id,
|
||||
sender: sender,
|
||||
origin_server_ts: origin_server_ts,
|
||||
unsigned: unsigned
|
||||
}) do
|
||||
data = %{
|
||||
content: content,
|
||||
type: type,
|
||||
event_id: event_id,
|
||||
sender: to_string(sender),
|
||||
origin_server_ts: origin_server_ts
|
||||
}
|
||||
|
||||
data = if unsigned, do: Map.put(data, :unsigned, unsigned), else: data
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
@spec as_pdu(Event.t()) :: map()
|
||||
def as_pdu(%Event{
|
||||
auth_events: auth_events,
|
||||
|
|
|
@ -70,8 +70,6 @@ defmodule Architex.Room do
|
|||
|
||||
@spec get_messages(Room.t(), Messages.t()) :: {[Event.t()], integer() | nil, integer() | nil}
|
||||
def get_messages(room, %Messages{from: from, to: to, dir: dir, limit: limit}) do
|
||||
limit = limit || 10
|
||||
|
||||
events =
|
||||
room
|
||||
|> Ecto.assoc(:events)
|
||||
|
@ -90,6 +88,8 @@ defmodule Architex.Room do
|
|||
|
||||
# When 'from' is empty, we return events from the start or end
|
||||
# of the room's history.
|
||||
# TODO: Might actually not be needed, could be that Quaternion is passing
|
||||
# an empty string because the /sync call fails.
|
||||
@spec events_from(Ecto.Query.t(), String.t(), String.t()) :: Ecto.Query.t()
|
||||
defp events_from(query, "", _), do: query
|
||||
|
||||
|
|
|
@ -249,7 +249,7 @@ defmodule ArchitexWeb.Client.RoomController do
|
|||
case Repo.one(room_query) do
|
||||
%Room{} = room ->
|
||||
{events, start, end_} = Room.get_messages(room, request)
|
||||
events = Enum.map(events, &Event.Formatters.for_client/1)
|
||||
events = Enum.map(events, &Event.Formatters.messages_response/1)
|
||||
data = %{chunk: events}
|
||||
data = if start, do: Map.put(data, :start, Integer.to_string(start)), else: data
|
||||
data = if end_, do: Map.put(data, :end, Integer.to_string(end_)), else: data
|
||||
|
|
73
lib/architex_web/client/controllers/sync_controller.ex
Normal file
73
lib/architex_web/client/controllers/sync_controller.ex
Normal file
|
@ -0,0 +1,73 @@
|
|||
defmodule ArchitexWeb.Client.SyncController do
|
||||
use ArchitexWeb, :controller
|
||||
|
||||
import ArchitexWeb.Error
|
||||
import Ecto.Query
|
||||
|
||||
alias Architex.{Repo, Event, Account, Room, JoinedRoom}
|
||||
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], jr in JoinedRoom,
|
||||
on: jr.room_id == e.room_id and jr.account_id == ^account_id
|
||||
)
|
||||
|> join(:inner, [e, jr], r in Room, on: r.id == jr.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
|
|
@ -14,7 +14,7 @@ defmodule ArchitexWeb.Client.Request.Messages do
|
|||
field :from, :string
|
||||
field :to, :string
|
||||
field :dir, :string
|
||||
field :limit, :integer
|
||||
field :limit, :integer, default: 10
|
||||
field :filter, :string
|
||||
end
|
||||
|
||||
|
|
14
lib/architex_web/client/request/sync.ex
Normal file
14
lib/architex_web/client/request/sync.ex
Normal file
|
@ -0,0 +1,14 @@
|
|||
defmodule ArchitexWeb.Client.Request.Sync do
|
||||
use ArchitexWeb.Request
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
@primary_key false
|
||||
embedded_schema do
|
||||
field :filter, :string
|
||||
field :since, :string
|
||||
field :full_state, :boolean, default: false
|
||||
field :set_presence, :string, default: "online"
|
||||
field :timeout, :integer, default: 0
|
||||
end
|
||||
end
|
|
@ -54,6 +54,7 @@ defmodule ArchitexWeb.Router do
|
|||
post "/createRoom", RoomController, :create
|
||||
get "/joined_rooms", RoomController, :joined_rooms
|
||||
get "/capabilities", InfoController, :capabilities
|
||||
get "/sync", SyncController, :sync
|
||||
|
||||
scope "/directory" do
|
||||
put "/room/:alias", AliasesController, :create
|
||||
|
|
Loading…
Reference in a new issue