Implement client joined rooms endpoint
Track which rooms a local account has joined Add some documentation to modules
This commit is contained in:
parent
9d40f8bc8b
commit
6f8c224d50
8 changed files with 95 additions and 11 deletions
|
@ -11,7 +11,7 @@ defmodule MatrixServer.RoomServer do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
alias MatrixServer.{Repo, Room, Event, StateResolution}
|
alias MatrixServer.{Repo, Room, Event, StateResolution, JoinedRoom, Account}
|
||||||
alias MatrixServer.StateResolution.Authorization
|
alias MatrixServer.StateResolution.Authorization
|
||||||
alias MatrixServerWeb.Client.Request.CreateRoom
|
alias MatrixServerWeb.Client.Request.CreateRoom
|
||||||
|
|
||||||
|
@ -199,6 +199,7 @@ defmodule MatrixServer.RoomServer do
|
||||||
join_creator <- Event.join(room, account, [create_room]),
|
join_creator <- Event.join(room, account, [create_room]),
|
||||||
{:ok, state_set, join_creator, room} <-
|
{:ok, state_set, join_creator, room} <-
|
||||||
verify_and_insert_event(join_creator, state_set, room),
|
verify_and_insert_event(join_creator, state_set, room),
|
||||||
|
{:ok, _} <- insert_joined_room_assoc(account, room),
|
||||||
pls <- Event.power_levels(room, account, [create_room, join_creator]),
|
pls <- Event.power_levels(room, account, [create_room, join_creator]),
|
||||||
{:ok, state_set, pls, room} <- verify_and_insert_event(pls, state_set, room) do
|
{:ok, state_set, pls, room} <- verify_and_insert_event(pls, state_set, room) do
|
||||||
auth_events = [create_room, join_creator, pls]
|
auth_events = [create_room, join_creator, pls]
|
||||||
|
@ -236,6 +237,10 @@ defmodule MatrixServer.RoomServer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp insert_joined_room_assoc(%Account{localpart: localpart}, %Room{id: room_id}) do
|
||||||
|
Repo.insert(%JoinedRoom{localpart: localpart, room_id: room_id})
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: trusted_private_chat:
|
# TODO: trusted_private_chat:
|
||||||
# All invitees are given the same power level as the room creator.
|
# All invitees are given the same power level as the room creator.
|
||||||
defp room_creation_preset(account, nil, %Room{visibility: visibility} = room, auth_events) do
|
defp room_creation_preset(account, nil, %Room{visibility: visibility} = room, auth_events) do
|
||||||
|
|
|
@ -3,7 +3,7 @@ defmodule MatrixServer.Account do
|
||||||
|
|
||||||
import Ecto.{Changeset, Query}
|
import Ecto.{Changeset, Query}
|
||||||
|
|
||||||
alias MatrixServer.{Repo, Account, Device}
|
alias MatrixServer.{Repo, Account, Device, Room, JoinedRoom}
|
||||||
alias MatrixServerWeb.Client.Request.{Register, Login}
|
alias MatrixServerWeb.Client.Request.{Register, Login}
|
||||||
alias Ecto.Multi
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ defmodule MatrixServer.Account do
|
||||||
schema "accounts" do
|
schema "accounts" do
|
||||||
field :password_hash, :string, redact: true
|
field :password_hash, :string, redact: true
|
||||||
has_many :devices, Device, foreign_key: :localpart
|
has_many :devices, Device, foreign_key: :localpart
|
||||||
|
|
||||||
|
many_to_many :joined_rooms, Room,
|
||||||
|
join_through: JoinedRoom,
|
||||||
|
join_keys: [localpart: :localpart, room_id: :id]
|
||||||
|
|
||||||
timestamps(updated_at: false)
|
timestamps(updated_at: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
16
lib/matrix_server/schema/joined_room.ex
Normal file
16
lib/matrix_server/schema/joined_room.ex
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
defmodule MatrixServer.JoinedRoom do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
alias MatrixServer.{Account, Room}
|
||||||
|
|
||||||
|
@primary_key false
|
||||||
|
schema "joined_rooms" do
|
||||||
|
belongs_to :account, Account,
|
||||||
|
foreign_key: :localpart,
|
||||||
|
references: :localpart,
|
||||||
|
type: :string,
|
||||||
|
primary_key: true
|
||||||
|
|
||||||
|
belongs_to :room, Room, primary_key: true, type: :string
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,4 +1,23 @@
|
||||||
defmodule MatrixServer.StateResolution do
|
defmodule MatrixServer.StateResolution do
|
||||||
|
@moduledoc """
|
||||||
|
Functions for resolving the state of a Matrix room.
|
||||||
|
|
||||||
|
Currently, only state resolution from room version 2 is supported,
|
||||||
|
see [the Matrix docs](https://spec.matrix.org/unstable/rooms/v2/).
|
||||||
|
|
||||||
|
The current implementation of the state resolution algorithm performs
|
||||||
|
rather badly.
|
||||||
|
Each time state is resolved, all events in the room are fetched from
|
||||||
|
the database and loaded into memory.
|
||||||
|
This is mostly so I didn't have to worry about fetching events from the
|
||||||
|
database when developing this initial implementation.
|
||||||
|
Then, the state is calculated using the new event's previous events and auth
|
||||||
|
events.
|
||||||
|
To prevent loading all events into memory, and calculating the whole state each
|
||||||
|
time, we should make snapshots of the state of a room at regular intervals.
|
||||||
|
It looks like Dendrite does this too.
|
||||||
|
"""
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
alias MatrixServer.{Repo, Event, Room}
|
alias MatrixServer.{Repo, Event, Room}
|
||||||
|
@ -61,6 +80,13 @@ defmodule MatrixServer.StateResolution do
|
||||||
|> Enum.reduce(MapSet.new(), &MapSet.union/2)
|
|> Enum.reduce(MapSet.new(), &MapSet.union/2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_state_set(
|
||||||
|
%Event{type: event_type, state_key: state_key} = event,
|
||||||
|
state_set
|
||||||
|
) do
|
||||||
|
Map.put(state_set, {event_type, state_key}, event)
|
||||||
|
end
|
||||||
|
|
||||||
defp do_resolve([], _), do: %{}
|
defp do_resolve([], _), do: %{}
|
||||||
|
|
||||||
defp do_resolve(state_sets, room_events) do
|
defp do_resolve(state_sets, room_events) do
|
||||||
|
@ -265,13 +291,6 @@ defmodule MatrixServer.StateResolution do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_state_set(
|
|
||||||
%Event{type: event_type, state_key: state_key} = event,
|
|
||||||
state_set
|
|
||||||
) do
|
|
||||||
Map.put(state_set, {event_type, state_key}, event)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp authorized?(%Event{auth_events: auth_event_ids} = event, state_set, room_events) do
|
defp authorized?(%Event{auth_events: auth_event_ids} = event, state_set, room_events) do
|
||||||
state_set =
|
state_set =
|
||||||
auth_event_ids
|
auth_event_ids
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
defmodule MatrixServer.StateResolution.Authorization do
|
defmodule MatrixServer.StateResolution.Authorization do
|
||||||
|
@moduledoc """
|
||||||
|
Implementation of Matrix event authorization rules for stat resolution.
|
||||||
|
|
||||||
|
Note that some authorization rules are already checked in
|
||||||
|
`MatrixServer.Event.prevalidate/1` so they are skipped here.
|
||||||
|
"""
|
||||||
|
|
||||||
import MatrixServer.StateResolution
|
import MatrixServer.StateResolution
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ defmodule MatrixServerWeb.Client.RoomController do
|
||||||
use MatrixServerWeb, :controller
|
use MatrixServerWeb, :controller
|
||||||
|
|
||||||
import MatrixServerWeb.Error
|
import MatrixServerWeb.Error
|
||||||
import Ecto.Changeset
|
import Ecto.{Changeset, Query}
|
||||||
|
|
||||||
alias MatrixServer.Room
|
alias MatrixServer.{Repo, Room}
|
||||||
alias MatrixServerWeb.Client.Request.CreateRoom
|
alias MatrixServerWeb.Client.Request.CreateRoom
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
alias Plug.Conn
|
alias Plug.Conn
|
||||||
|
@ -31,4 +31,19 @@ defmodule MatrixServerWeb.Client.RoomController do
|
||||||
put_error(conn, :bad_json)
|
put_error(conn, :bad_json)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def joined_rooms(%Conn{assigns: %{account: account}} = conn, _params) do
|
||||||
|
joined_room_ids = account
|
||||||
|
|> Ecto.assoc(:joined_rooms)
|
||||||
|
|> select([jr], jr.id)
|
||||||
|
|> Repo.all()
|
||||||
|
|
||||||
|
data = %{
|
||||||
|
joined_rooms: joined_room_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_status(200)
|
||||||
|
|> json(data)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,6 +51,7 @@ defmodule MatrixServerWeb.Router do
|
||||||
post "/logout", AccountController, :logout
|
post "/logout", AccountController, :logout
|
||||||
post "/logout/all", AccountController, :logout_all
|
post "/logout/all", AccountController, :logout_all
|
||||||
post "/createRoom", RoomController, :create
|
post "/createRoom", RoomController, :create
|
||||||
|
get "/joined_rooms", RoomController, :joined_rooms
|
||||||
|
|
||||||
scope "/directory/room" do
|
scope "/directory/room" do
|
||||||
put "/:alias", AliasesController, :create
|
put "/:alias", AliasesController, :create
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
defmodule MatrixServer.Repo.Migrations.CreateJoinedRoomsTable do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create table(:joined_rooms, primary_key: false) do
|
||||||
|
add :localpart,
|
||||||
|
references(:accounts, column: :localpart, type: :string),
|
||||||
|
primary_key: true,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
add :room_id, references(:rooms, type: :string),
|
||||||
|
primary_key: true,
|
||||||
|
null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue