Implement client get room stat endpoint

This commit is contained in:
Pim Kunis 2021-09-14 14:39:22 +02:00
parent 739c496ac6
commit 222b6a309a
5 changed files with 97 additions and 31 deletions

View file

@ -61,6 +61,7 @@ Here, implemented and some unimplemented features are listed.
- PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey} - PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}
- PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId} - PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}
- GET /_matrix/client/r0/rooms/{roomId}/messages: Except filtering. - GET /_matrix/client/r0/rooms/{roomId}/messages: Except filtering.
- GET /_matrix/client/r0/rooms/{roomId}/state
- GET /_matrix/client/r0/directory/list/room/{roomId} - GET /_matrix/client/r0/directory/list/room/{roomId}
- PUT /_matrix/client/r0/directory/list/room/{roomId} - PUT /_matrix/client/r0/directory/list/room/{roomId}
- GET /_matrix/client/r0/capabilities - GET /_matrix/client/r0/capabilities

View file

@ -189,6 +189,17 @@ defmodule Architex.RoomServer do
GenServer.call(pid, {:send_state_event, account, event_type, content, state_key}) GenServer.call(pid, {:send_state_event, account, event_type, content, state_key})
end end
@doc """
Get the current state of a room.
If the requesting user is not a member of the room,
get the state when the user left the room.
If the user has never been in the room, return an error.
"""
@spec get_current_state(pid(), Account.t()) :: {:ok, [Event.t()]} | :error
def get_current_state(pid, account) do
GenServer.call(pid, {:get_current_state, account})
end
### Implementation ### Implementation
@impl true @impl true
@ -424,6 +435,24 @@ defmodule Architex.RoomServer do
end end
end end
def handle_call({:get_current_state, account}, _from, %{state_set: state_set} = state) do
mxid = Account.get_mxid(account)
case state_set[{"m.room.member", mxid}] do
%Event{content: %{"membership" => "join"}} ->
# Get the current state of the room.
{:reply, {:ok, Map.values(state_set)}, state}
%Event{content: %{"membership" => "leave"}} = event ->
# Get the state of the room, after leaving.
state_set = StateResolution.resolve(event)
{:reply, {:ok, Map.values(state_set)}, state}
_ ->
{:reply, :error, state}
end
end
@spec process_event_with_txn(t(), Room.t(), Device.t(), %Event{}, String.t()) :: @spec process_event_with_txn(t(), Room.t(), Device.t(), %Event{}, String.t()) ::
(() -> {t(), Room.t(), String.t()} | {:error, atom()}) (() -> {t(), Room.t(), String.t()} | {:error, atom()})
defp process_event_with_txn( defp process_event_with_txn(

View file

@ -4,33 +4,10 @@ defmodule Architex.Event.Formatters do
""" """
alias Architex.Event alias Architex.Event
@spec messages_response(Event.t()) :: map() @doc """
def messages_response(%Event{ Event format with keys that all formats have in common.
content: content, """
type: type, def base_client_response(%Event{
id: event_id,
sender: sender,
origin_server_ts: origin_server_ts,
unsigned: unsigned,
room_id: room_id,
state_key: state_key
}) do
data = %{
content: content,
type: type,
event_id: event_id,
sender: to_string(sender),
origin_server_ts: origin_server_ts,
room_id: room_id
}
data = if unsigned, do: Map.put(data, :unsigned, unsigned), else: data
data = if state_key, do: Map.put(data, :state_key, state_key), else: data
data
end
def sync_response(%Event{
content: content, content: content,
type: type, type: type,
id: event_id, id: event_id,
@ -46,11 +23,37 @@ defmodule Architex.Event.Formatters do
origin_server_ts: origin_server_ts origin_server_ts: origin_server_ts
} }
data = if unsigned, do: Map.put(data, :unsigned, unsigned), else: data if unsigned, do: Map.put(data, :unsigned, unsigned), else: data
data
end end
@doc """
The base event format, with room_id and state_key added.
Used in the client /messages response.
"""
@spec messages_response(Event.t()) :: map()
def messages_response(%Event{room_id: room_id, state_key: state_key} = event) do
data =
base_client_response(event)
|> Map.put(:room_id, room_id)
if state_key, do: Map.put(data, :state_key, state_key), else: data
end
@doc """
The event format used in the client /state response.
TODO: prev_content
"""
def state_response(event), do: messages_response(event)
@doc """
The base event format, used in the client /sync response.
"""
@spec sync_response(Event.t()) :: map()
def sync_response(event), do: base_client_response(event)
@doc """
The PDU format used for federation.
"""
@spec as_pdu(Event.t()) :: map() @spec as_pdu(Event.t()) :: map()
def as_pdu(%Event{ def as_pdu(%Event{
auth_events: auth_events, auth_events: auth_events,

View file

@ -311,4 +311,33 @@ defmodule ArchitexWeb.Client.RoomController do
{:error, _} -> put_error(conn, :bad_json) {:error, _} -> put_error(conn, :bad_json)
end end
end end
@doc """
Get the state events for the current state of a room.
Action for GET /_matrix/client/r0/rooms/{roomId}/state.
"""
def state(%Conn{assigns: %{account: account}} = conn, %{"room_id" => room_id}) do
case RoomServer.get_room_server(room_id) do
{:ok, pid} ->
case RoomServer.get_current_state(pid, account) do
{:ok, events} ->
events = Enum.map(events, &Event.Formatters.state_response/1)
conn
|> put_status(200)
|> json(events)
:error ->
put_error(
conn,
:forbidden,
"You aren't a member of the room and weren't previously a member of the room."
)
end
{:error, :not_found} ->
put_error(conn, :not_found, "The given room was not found.")
end
end
end end

View file

@ -87,7 +87,11 @@ defmodule ArchitexWeb.Router do
post "/unban", RoomController, :unban post "/unban", RoomController, :unban
put "/send/:event_type/:txn_id", RoomController, :send_message_event put "/send/:event_type/:txn_id", RoomController, :send_message_event
get "/messages", RoomController, :messages get "/messages", RoomController, :messages
put "/state/:event_type/*state_key", RoomController, :send_state_event
scope "/state" do
get "/", RoomController, :state
put "/:event_type/*state_key", RoomController, :send_state_event
end
end end
end end
end end