__init__.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. # Copyright 2018 New Vector Ltd
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. from twisted.internet import defer
  17. from synapse.storage.devices import DeviceStore
  18. from .appservice import (
  19. ApplicationServiceStore, ApplicationServiceTransactionStore
  20. )
  21. from .directory import DirectoryStore
  22. from .events import EventsStore
  23. from .presence import PresenceStore, UserPresenceState
  24. from .profile import ProfileStore
  25. from .registration import RegistrationStore
  26. from .room import RoomStore
  27. from .roommember import RoomMemberStore
  28. from .stream import StreamStore
  29. from .transactions import TransactionStore
  30. from .keys import KeyStore
  31. from .event_federation import EventFederationStore
  32. from .pusher import PusherStore
  33. from .push_rule import PushRuleStore
  34. from .media_repository import MediaRepositoryStore
  35. from .rejections import RejectionsStore
  36. from .event_push_actions import EventPushActionsStore
  37. from .deviceinbox import DeviceInboxStore
  38. from .group_server import GroupServerStore
  39. from .state import StateStore
  40. from .signatures import SignatureStore
  41. from .filtering import FilteringStore
  42. from .end_to_end_keys import EndToEndKeyStore
  43. from .receipts import ReceiptsStore
  44. from .search import SearchStore
  45. from .tags import TagsStore
  46. from .account_data import AccountDataStore
  47. from .openid import OpenIdStore
  48. from .client_ips import ClientIpStore
  49. from .user_directory import UserDirectoryStore
  50. from .util.id_generators import IdGenerator, StreamIdGenerator, ChainedIdGenerator
  51. from .engines import PostgresEngine
  52. from synapse.api.constants import PresenceState
  53. from synapse.util.caches.stream_change_cache import StreamChangeCache
  54. import logging
  55. logger = logging.getLogger(__name__)
  56. class DataStore(RoomMemberStore, RoomStore,
  57. RegistrationStore, StreamStore, ProfileStore,
  58. PresenceStore, TransactionStore,
  59. DirectoryStore, KeyStore, StateStore, SignatureStore,
  60. ApplicationServiceStore,
  61. EventFederationStore,
  62. MediaRepositoryStore,
  63. RejectionsStore,
  64. FilteringStore,
  65. PusherStore,
  66. PushRuleStore,
  67. ApplicationServiceTransactionStore,
  68. EventsStore,
  69. ReceiptsStore,
  70. EndToEndKeyStore,
  71. SearchStore,
  72. TagsStore,
  73. AccountDataStore,
  74. EventPushActionsStore,
  75. OpenIdStore,
  76. ClientIpStore,
  77. DeviceStore,
  78. DeviceInboxStore,
  79. UserDirectoryStore,
  80. GroupServerStore,
  81. ):
  82. def __init__(self, db_conn, hs):
  83. self.hs = hs
  84. self._clock = hs.get_clock()
  85. self.database_engine = hs.database_engine
  86. self._stream_id_gen = StreamIdGenerator(
  87. db_conn, "events", "stream_ordering",
  88. extra_tables=[("local_invites", "stream_id")]
  89. )
  90. self._backfill_id_gen = StreamIdGenerator(
  91. db_conn, "events", "stream_ordering", step=-1,
  92. extra_tables=[("ex_outlier_stream", "event_stream_ordering")]
  93. )
  94. self._presence_id_gen = StreamIdGenerator(
  95. db_conn, "presence_stream", "stream_id"
  96. )
  97. self._device_inbox_id_gen = StreamIdGenerator(
  98. db_conn, "device_max_stream_id", "stream_id"
  99. )
  100. self._public_room_id_gen = StreamIdGenerator(
  101. db_conn, "public_room_list_stream", "stream_id"
  102. )
  103. self._device_list_id_gen = StreamIdGenerator(
  104. db_conn, "device_lists_stream", "stream_id",
  105. )
  106. self._transaction_id_gen = IdGenerator(db_conn, "sent_transactions", "id")
  107. self._access_tokens_id_gen = IdGenerator(db_conn, "access_tokens", "id")
  108. self._event_reports_id_gen = IdGenerator(db_conn, "event_reports", "id")
  109. self._push_rule_id_gen = IdGenerator(db_conn, "push_rules", "id")
  110. self._push_rules_enable_id_gen = IdGenerator(db_conn, "push_rules_enable", "id")
  111. self._push_rules_stream_id_gen = ChainedIdGenerator(
  112. self._stream_id_gen, db_conn, "push_rules_stream", "stream_id"
  113. )
  114. self._pushers_id_gen = StreamIdGenerator(
  115. db_conn, "pushers", "id",
  116. extra_tables=[("deleted_pushers", "stream_id")],
  117. )
  118. self._group_updates_id_gen = StreamIdGenerator(
  119. db_conn, "local_group_updates", "stream_id",
  120. )
  121. if isinstance(self.database_engine, PostgresEngine):
  122. self._cache_id_gen = StreamIdGenerator(
  123. db_conn, "cache_invalidation_stream", "stream_id",
  124. )
  125. else:
  126. self._cache_id_gen = None
  127. self._presence_on_startup = self._get_active_presence(db_conn)
  128. presence_cache_prefill, min_presence_val = self._get_cache_dict(
  129. db_conn, "presence_stream",
  130. entity_column="user_id",
  131. stream_column="stream_id",
  132. max_value=self._presence_id_gen.get_current_token(),
  133. )
  134. self.presence_stream_cache = StreamChangeCache(
  135. "PresenceStreamChangeCache", min_presence_val,
  136. prefilled_cache=presence_cache_prefill
  137. )
  138. max_device_inbox_id = self._device_inbox_id_gen.get_current_token()
  139. device_inbox_prefill, min_device_inbox_id = self._get_cache_dict(
  140. db_conn, "device_inbox",
  141. entity_column="user_id",
  142. stream_column="stream_id",
  143. max_value=max_device_inbox_id,
  144. limit=1000,
  145. )
  146. self._device_inbox_stream_cache = StreamChangeCache(
  147. "DeviceInboxStreamChangeCache", min_device_inbox_id,
  148. prefilled_cache=device_inbox_prefill,
  149. )
  150. # The federation outbox and the local device inbox uses the same
  151. # stream_id generator.
  152. device_outbox_prefill, min_device_outbox_id = self._get_cache_dict(
  153. db_conn, "device_federation_outbox",
  154. entity_column="destination",
  155. stream_column="stream_id",
  156. max_value=max_device_inbox_id,
  157. limit=1000,
  158. )
  159. self._device_federation_outbox_stream_cache = StreamChangeCache(
  160. "DeviceFederationOutboxStreamChangeCache", min_device_outbox_id,
  161. prefilled_cache=device_outbox_prefill,
  162. )
  163. device_list_max = self._device_list_id_gen.get_current_token()
  164. self._device_list_stream_cache = StreamChangeCache(
  165. "DeviceListStreamChangeCache", device_list_max,
  166. )
  167. self._device_list_federation_stream_cache = StreamChangeCache(
  168. "DeviceListFederationStreamChangeCache", device_list_max,
  169. )
  170. events_max = self._stream_id_gen.get_current_token()
  171. curr_state_delta_prefill, min_curr_state_delta_id = self._get_cache_dict(
  172. db_conn, "current_state_delta_stream",
  173. entity_column="room_id",
  174. stream_column="stream_id",
  175. max_value=events_max, # As we share the stream id with events token
  176. limit=1000,
  177. )
  178. self._curr_state_delta_stream_cache = StreamChangeCache(
  179. "_curr_state_delta_stream_cache", min_curr_state_delta_id,
  180. prefilled_cache=curr_state_delta_prefill,
  181. )
  182. _group_updates_prefill, min_group_updates_id = self._get_cache_dict(
  183. db_conn, "local_group_updates",
  184. entity_column="user_id",
  185. stream_column="stream_id",
  186. max_value=self._group_updates_id_gen.get_current_token(),
  187. limit=1000,
  188. )
  189. self._group_updates_stream_cache = StreamChangeCache(
  190. "_group_updates_stream_cache", min_group_updates_id,
  191. prefilled_cache=_group_updates_prefill,
  192. )
  193. self._stream_order_on_start = self.get_room_max_stream_ordering()
  194. self._min_stream_order_on_start = self.get_room_min_stream_ordering()
  195. super(DataStore, self).__init__(db_conn, hs)
  196. def take_presence_startup_info(self):
  197. active_on_startup = self._presence_on_startup
  198. self._presence_on_startup = None
  199. return active_on_startup
  200. def _get_active_presence(self, db_conn):
  201. """Fetch non-offline presence from the database so that we can register
  202. the appropriate time outs.
  203. """
  204. sql = (
  205. "SELECT user_id, state, last_active_ts, last_federation_update_ts,"
  206. " last_user_sync_ts, status_msg, currently_active FROM presence_stream"
  207. " WHERE state != ?"
  208. )
  209. sql = self.database_engine.convert_param_style(sql)
  210. txn = db_conn.cursor()
  211. txn.execute(sql, (PresenceState.OFFLINE,))
  212. rows = self.cursor_to_dict(txn)
  213. txn.close()
  214. for row in rows:
  215. row["currently_active"] = bool(row["currently_active"])
  216. return [UserPresenceState(**row) for row in rows]
  217. @defer.inlineCallbacks
  218. def count_daily_users(self):
  219. """
  220. Counts the number of users who used this homeserver in the last 24 hours.
  221. """
  222. def _count_users(txn):
  223. yesterday = int(self._clock.time_msec()) - (1000 * 60 * 60 * 24),
  224. sql = """
  225. SELECT COALESCE(count(*), 0) FROM (
  226. SELECT user_id FROM user_ips
  227. WHERE last_seen > ?
  228. GROUP BY user_id
  229. ) u
  230. """
  231. txn.execute(sql, (yesterday,))
  232. count, = txn.fetchone()
  233. return count
  234. ret = yield self.runInteraction("count_users", _count_users)
  235. defer.returnValue(ret)
  236. def get_users(self):
  237. """Function to reterive a list of users in users table.
  238. Args:
  239. Returns:
  240. defer.Deferred: resolves to list[dict[str, Any]]
  241. """
  242. return self._simple_select_list(
  243. table="users",
  244. keyvalues={},
  245. retcols=[
  246. "name",
  247. "password_hash",
  248. "is_guest",
  249. "admin"
  250. ],
  251. desc="get_users",
  252. )
  253. def get_users_paginate(self, order, start, limit):
  254. """Function to reterive a paginated list of users from
  255. users list. This will return a json object, which contains
  256. list of users and the total number of users in users table.
  257. Args:
  258. order (str): column name to order the select by this column
  259. start (int): start number to begin the query from
  260. limit (int): number of rows to reterive
  261. Returns:
  262. defer.Deferred: resolves to json object {list[dict[str, Any]], count}
  263. """
  264. is_guest = 0
  265. i_start = (int)(start)
  266. i_limit = (int)(limit)
  267. return self.get_user_list_paginate(
  268. table="users",
  269. keyvalues={
  270. "is_guest": is_guest
  271. },
  272. pagevalues=[
  273. order,
  274. i_limit,
  275. i_start
  276. ],
  277. retcols=[
  278. "name",
  279. "password_hash",
  280. "is_guest",
  281. "admin"
  282. ],
  283. desc="get_users_paginate",
  284. )
  285. def search_users(self, term):
  286. """Function to search users list for one or more users with
  287. the matched term.
  288. Args:
  289. term (str): search term
  290. col (str): column to query term should be matched to
  291. Returns:
  292. defer.Deferred: resolves to list[dict[str, Any]]
  293. """
  294. return self._simple_search_list(
  295. table="users",
  296. term=term,
  297. col="name",
  298. retcols=[
  299. "name",
  300. "password_hash",
  301. "is_guest",
  302. "admin"
  303. ],
  304. desc="search_users",
  305. )
  306. def are_all_users_on_domain(txn, database_engine, domain):
  307. sql = database_engine.convert_param_style(
  308. "SELECT COUNT(*) FROM users WHERE name NOT LIKE ?"
  309. )
  310. pat = "%:" + domain
  311. txn.execute(sql, (pat,))
  312. num_not_matching = txn.fetchall()[0][0]
  313. if num_not_matching == 0:
  314. return True
  315. return False