mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-06-24 19:00:27 -04:00
Merge pull request #2466 from matrix-org/erikj/groups_merged
Initial Group Implementation
This commit is contained in:
commit
535cc49f27
35 changed files with 4793 additions and 66 deletions
|
@ -37,7 +37,7 @@ from .media_repository import MediaRepositoryStore
|
|||
from .rejections import RejectionsStore
|
||||
from .event_push_actions import EventPushActionsStore
|
||||
from .deviceinbox import DeviceInboxStore
|
||||
|
||||
from .group_server import GroupServerStore
|
||||
from .state import StateStore
|
||||
from .signatures import SignatureStore
|
||||
from .filtering import FilteringStore
|
||||
|
@ -88,6 +88,7 @@ class DataStore(RoomMemberStore, RoomStore,
|
|||
DeviceStore,
|
||||
DeviceInboxStore,
|
||||
UserDirectoryStore,
|
||||
GroupServerStore,
|
||||
):
|
||||
|
||||
def __init__(self, db_conn, hs):
|
||||
|
@ -135,6 +136,9 @@ class DataStore(RoomMemberStore, RoomStore,
|
|||
db_conn, "pushers", "id",
|
||||
extra_tables=[("deleted_pushers", "stream_id")],
|
||||
)
|
||||
self._group_updates_id_gen = StreamIdGenerator(
|
||||
db_conn, "local_group_updates", "stream_id",
|
||||
)
|
||||
|
||||
if isinstance(self.database_engine, PostgresEngine):
|
||||
self._cache_id_gen = StreamIdGenerator(
|
||||
|
@ -235,6 +239,18 @@ class DataStore(RoomMemberStore, RoomStore,
|
|||
prefilled_cache=curr_state_delta_prefill,
|
||||
)
|
||||
|
||||
_group_updates_prefill, min_group_updates_id = self._get_cache_dict(
|
||||
db_conn, "local_group_updates",
|
||||
entity_column="user_id",
|
||||
stream_column="stream_id",
|
||||
max_value=self._group_updates_id_gen.get_current_token(),
|
||||
limit=1000,
|
||||
)
|
||||
self._group_updates_stream_cache = StreamChangeCache(
|
||||
"_group_updates_stream_cache", min_group_updates_id,
|
||||
prefilled_cache=_group_updates_prefill,
|
||||
)
|
||||
|
||||
cur = LoggingTransaction(
|
||||
db_conn.cursor(),
|
||||
name="_find_stream_orderings_for_times_txn",
|
||||
|
|
|
@ -743,6 +743,33 @@ class SQLBaseStore(object):
|
|||
txn.execute(sql, values)
|
||||
return cls.cursor_to_dict(txn)
|
||||
|
||||
def _simple_update(self, table, keyvalues, updatevalues, desc):
|
||||
return self.runInteraction(
|
||||
desc,
|
||||
self._simple_update_txn,
|
||||
table, keyvalues, updatevalues,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _simple_update_txn(txn, table, keyvalues, updatevalues):
|
||||
if keyvalues:
|
||||
where = "WHERE %s" % " AND ".join("%s = ?" % k for k in keyvalues.iterkeys())
|
||||
else:
|
||||
where = ""
|
||||
|
||||
update_sql = "UPDATE %s SET %s %s" % (
|
||||
table,
|
||||
", ".join("%s = ?" % (k,) for k in updatevalues),
|
||||
where,
|
||||
)
|
||||
|
||||
txn.execute(
|
||||
update_sql,
|
||||
updatevalues.values() + keyvalues.values()
|
||||
)
|
||||
|
||||
return txn.rowcount
|
||||
|
||||
def _simple_update_one(self, table, keyvalues, updatevalues,
|
||||
desc="_simple_update_one"):
|
||||
"""Executes an UPDATE query on the named table, setting new values for
|
||||
|
@ -768,27 +795,13 @@ class SQLBaseStore(object):
|
|||
table, keyvalues, updatevalues,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _simple_update_one_txn(txn, table, keyvalues, updatevalues):
|
||||
if keyvalues:
|
||||
where = "WHERE %s" % " AND ".join("%s = ?" % k for k in keyvalues.iterkeys())
|
||||
else:
|
||||
where = ""
|
||||
@classmethod
|
||||
def _simple_update_one_txn(cls, txn, table, keyvalues, updatevalues):
|
||||
rowcount = cls._simple_update_txn(txn, table, keyvalues, updatevalues)
|
||||
|
||||
update_sql = "UPDATE %s SET %s %s" % (
|
||||
table,
|
||||
", ".join("%s = ?" % (k,) for k in updatevalues),
|
||||
where,
|
||||
)
|
||||
|
||||
txn.execute(
|
||||
update_sql,
|
||||
updatevalues.values() + keyvalues.values()
|
||||
)
|
||||
|
||||
if txn.rowcount == 0:
|
||||
if rowcount == 0:
|
||||
raise StoreError(404, "No row found")
|
||||
if txn.rowcount > 1:
|
||||
if rowcount > 1:
|
||||
raise StoreError(500, "More than one row matched")
|
||||
|
||||
@staticmethod
|
||||
|
|
1187
synapse/storage/group_server.py
Normal file
1187
synapse/storage/group_server.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
from ._base import SQLBaseStore
|
||||
|
||||
|
||||
|
@ -55,3 +57,99 @@ class ProfileStore(SQLBaseStore):
|
|||
updatevalues={"avatar_url": new_avatar_url},
|
||||
desc="set_profile_avatar_url",
|
||||
)
|
||||
|
||||
def get_from_remote_profile_cache(self, user_id):
|
||||
return self._simple_select_one(
|
||||
table="remote_profile_cache",
|
||||
keyvalues={"user_id": user_id},
|
||||
retcols=("displayname", "avatar_url",),
|
||||
allow_none=True,
|
||||
desc="get_from_remote_profile_cache",
|
||||
)
|
||||
|
||||
def add_remote_profile_cache(self, user_id, displayname, avatar_url):
|
||||
"""Ensure we are caching the remote user's profiles.
|
||||
|
||||
This should only be called when `is_subscribed_remote_profile_for_user`
|
||||
would return true for the user.
|
||||
"""
|
||||
return self._simple_upsert(
|
||||
table="remote_profile_cache",
|
||||
keyvalues={"user_id": user_id},
|
||||
values={
|
||||
"displayname": displayname,
|
||||
"avatar_url": avatar_url,
|
||||
"last_check": self._clock.time_msec(),
|
||||
},
|
||||
desc="add_remote_profile_cache",
|
||||
)
|
||||
|
||||
def update_remote_profile_cache(self, user_id, displayname, avatar_url):
|
||||
return self._simple_update(
|
||||
table="remote_profile_cache",
|
||||
keyvalues={"user_id": user_id},
|
||||
values={
|
||||
"displayname": displayname,
|
||||
"avatar_url": avatar_url,
|
||||
"last_check": self._clock.time_msec(),
|
||||
},
|
||||
desc="update_remote_profile_cache",
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def maybe_delete_remote_profile_cache(self, user_id):
|
||||
"""Check if we still care about the remote user's profile, and if we
|
||||
don't then remove their profile from the cache
|
||||
"""
|
||||
subscribed = yield self.is_subscribed_remote_profile_for_user(user_id)
|
||||
if not subscribed:
|
||||
yield self._simple_delete(
|
||||
table="remote_profile_cache",
|
||||
keyvalues={"user_id": user_id},
|
||||
desc="delete_remote_profile_cache",
|
||||
)
|
||||
|
||||
def get_remote_profile_cache_entries_that_expire(self, last_checked):
|
||||
"""Get all users who haven't been checked since `last_checked`
|
||||
"""
|
||||
def _get_remote_profile_cache_entries_that_expire_txn(txn):
|
||||
sql = """
|
||||
SELECT user_id, displayname, avatar_url
|
||||
FROM remote_profile_cache
|
||||
WHERE last_check < ?
|
||||
"""
|
||||
|
||||
txn.execute(sql, (last_checked,))
|
||||
|
||||
return self.cursor_to_dict(txn)
|
||||
|
||||
return self.runInteraction(
|
||||
"get_remote_profile_cache_entries_that_expire",
|
||||
_get_remote_profile_cache_entries_that_expire_txn,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def is_subscribed_remote_profile_for_user(self, user_id):
|
||||
"""Check whether we are interested in a remote user's profile.
|
||||
"""
|
||||
res = yield self._simple_select_one_onecol(
|
||||
table="group_users",
|
||||
keyvalues={"user_id": user_id},
|
||||
retcol="user_id",
|
||||
allow_none=True,
|
||||
desc="should_update_remote_profile_cache_for_user",
|
||||
)
|
||||
|
||||
if res:
|
||||
defer.returnValue(True)
|
||||
|
||||
res = yield self._simple_select_one_onecol(
|
||||
table="group_invites",
|
||||
keyvalues={"user_id": user_id},
|
||||
retcol="user_id",
|
||||
allow_none=True,
|
||||
desc="should_update_remote_profile_cache_for_user",
|
||||
)
|
||||
|
||||
if res:
|
||||
defer.returnValue(True)
|
||||
|
|
167
synapse/storage/schema/delta/43/group_server.sql
Normal file
167
synapse/storage/schema/delta/43/group_server.sql
Normal file
|
@ -0,0 +1,167 @@
|
|||
/* Copyright 2017 Vector Creations Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
CREATE TABLE groups (
|
||||
group_id TEXT NOT NULL,
|
||||
name TEXT, -- the display name of the room
|
||||
avatar_url TEXT,
|
||||
short_description TEXT,
|
||||
long_description TEXT
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX groups_idx ON groups(group_id);
|
||||
|
||||
|
||||
-- list of users the group server thinks are joined
|
||||
CREATE TABLE group_users (
|
||||
group_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
is_admin BOOLEAN NOT NULL,
|
||||
is_public BOOLEAN NOT NULL -- whether the users membership can be seen by everyone
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX groups_users_g_idx ON group_users(group_id, user_id);
|
||||
CREATE INDEX groups_users_u_idx ON group_users(user_id);
|
||||
|
||||
-- list of users the group server thinks are invited
|
||||
CREATE TABLE group_invites (
|
||||
group_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX groups_invites_g_idx ON group_invites(group_id, user_id);
|
||||
CREATE INDEX groups_invites_u_idx ON group_invites(user_id);
|
||||
|
||||
|
||||
CREATE TABLE group_rooms (
|
||||
group_id TEXT NOT NULL,
|
||||
room_id TEXT NOT NULL,
|
||||
is_public BOOLEAN NOT NULL -- whether the room can be seen by everyone
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX groups_rooms_g_idx ON group_rooms(group_id, room_id);
|
||||
CREATE INDEX groups_rooms_r_idx ON group_rooms(room_id);
|
||||
|
||||
|
||||
-- Rooms to include in the summary
|
||||
CREATE TABLE group_summary_rooms (
|
||||
group_id TEXT NOT NULL,
|
||||
room_id TEXT NOT NULL,
|
||||
category_id TEXT NOT NULL,
|
||||
room_order BIGINT NOT NULL,
|
||||
is_public BOOLEAN NOT NULL, -- whether the room should be show to everyone
|
||||
UNIQUE (group_id, category_id, room_id, room_order),
|
||||
CHECK (room_order > 0)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX group_summary_rooms_g_idx ON group_summary_rooms(group_id, room_id, category_id);
|
||||
|
||||
|
||||
-- Categories to include in the summary
|
||||
CREATE TABLE group_summary_room_categories (
|
||||
group_id TEXT NOT NULL,
|
||||
category_id TEXT NOT NULL,
|
||||
cat_order BIGINT NOT NULL,
|
||||
UNIQUE (group_id, category_id, cat_order),
|
||||
CHECK (cat_order > 0)
|
||||
);
|
||||
|
||||
-- The categories in the group
|
||||
CREATE TABLE group_room_categories (
|
||||
group_id TEXT NOT NULL,
|
||||
category_id TEXT NOT NULL,
|
||||
profile TEXT NOT NULL,
|
||||
is_public BOOLEAN NOT NULL, -- whether the category should be show to everyone
|
||||
UNIQUE (group_id, category_id)
|
||||
);
|
||||
|
||||
-- The users to include in the group summary
|
||||
CREATE TABLE group_summary_users (
|
||||
group_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
role_id TEXT NOT NULL,
|
||||
user_order BIGINT NOT NULL,
|
||||
is_public BOOLEAN NOT NULL -- whether the user should be show to everyone
|
||||
);
|
||||
|
||||
CREATE INDEX group_summary_users_g_idx ON group_summary_users(group_id);
|
||||
|
||||
-- The roles to include in the group summary
|
||||
CREATE TABLE group_summary_roles (
|
||||
group_id TEXT NOT NULL,
|
||||
role_id TEXT NOT NULL,
|
||||
role_order BIGINT NOT NULL,
|
||||
UNIQUE (group_id, role_id, role_order),
|
||||
CHECK (role_order > 0)
|
||||
);
|
||||
|
||||
|
||||
-- The roles in a groups
|
||||
CREATE TABLE group_roles (
|
||||
group_id TEXT NOT NULL,
|
||||
role_id TEXT NOT NULL,
|
||||
profile TEXT NOT NULL,
|
||||
is_public BOOLEAN NOT NULL, -- whether the role should be show to everyone
|
||||
UNIQUE (group_id, role_id)
|
||||
);
|
||||
|
||||
|
||||
-- List of attestations we've given out and need to renew
|
||||
CREATE TABLE group_attestations_renewals (
|
||||
group_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
valid_until_ms BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX group_attestations_renewals_g_idx ON group_attestations_renewals(group_id, user_id);
|
||||
CREATE INDEX group_attestations_renewals_u_idx ON group_attestations_renewals(user_id);
|
||||
CREATE INDEX group_attestations_renewals_v_idx ON group_attestations_renewals(valid_until_ms);
|
||||
|
||||
|
||||
-- List of attestations we've received from remotes and are interested in.
|
||||
CREATE TABLE group_attestations_remote (
|
||||
group_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
valid_until_ms BIGINT NOT NULL,
|
||||
attestation_json TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX group_attestations_remote_g_idx ON group_attestations_remote(group_id, user_id);
|
||||
CREATE INDEX group_attestations_remote_u_idx ON group_attestations_remote(user_id);
|
||||
CREATE INDEX group_attestations_remote_v_idx ON group_attestations_remote(valid_until_ms);
|
||||
|
||||
|
||||
-- The group membership for the HS's users
|
||||
CREATE TABLE local_group_membership (
|
||||
group_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
is_admin BOOLEAN NOT NULL,
|
||||
membership TEXT NOT NULL,
|
||||
is_publicised BOOLEAN NOT NULL, -- if the user is publicising their membership
|
||||
content TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX local_group_membership_u_idx ON local_group_membership(user_id, group_id);
|
||||
CREATE INDEX local_group_membership_g_idx ON local_group_membership(group_id);
|
||||
|
||||
|
||||
CREATE TABLE local_group_updates (
|
||||
stream_id BIGINT NOT NULL,
|
||||
group_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
content TEXT NOT NULL
|
||||
);
|
28
synapse/storage/schema/delta/43/profile_cache.sql
Normal file
28
synapse/storage/schema/delta/43/profile_cache.sql
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* Copyright 2017 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
-- A subset of remote users whose profiles we have cached.
|
||||
-- Whether a user is in this table or not is defined by the storage function
|
||||
-- `is_subscribed_remote_profile_for_user`
|
||||
CREATE TABLE remote_profile_cache (
|
||||
user_id TEXT NOT NULL,
|
||||
displayname TEXT,
|
||||
avatar_url TEXT,
|
||||
last_check BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX remote_profile_cache_user_id ON remote_profile_cache(user_id);
|
||||
CREATE INDEX remote_profile_cache_time ON remote_profile_cache(last_check);
|
Loading…
Add table
Add a link
Reference in a new issue