client.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014, 2015 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from twisted.internet import defer
  16. from synapse.api.constants import Membership
  17. from synapse.api.urls import FEDERATION_PREFIX as PREFIX
  18. from synapse.util.logutils import log_function
  19. import logging
  20. logger = logging.getLogger(__name__)
  21. class TransportLayerClient(object):
  22. """Sends federation HTTP requests to other servers"""
  23. @log_function
  24. def get_room_state(self, destination, room_id, event_id):
  25. """ Requests all state for a given room from the given server at the
  26. given event.
  27. Args:
  28. destination (str): The host name of the remote home server we want
  29. to get the state from.
  30. context (str): The name of the context we want the state of
  31. event_id (str): The event we want the context at.
  32. Returns:
  33. Deferred: Results in a dict received from the remote homeserver.
  34. """
  35. logger.debug("get_room_state dest=%s, room=%s",
  36. destination, room_id)
  37. path = PREFIX + "/state/%s/" % room_id
  38. return self.client.get_json(
  39. destination, path=path, args={"event_id": event_id},
  40. )
  41. @log_function
  42. def get_event(self, destination, event_id, timeout=None):
  43. """ Requests the pdu with give id and origin from the given server.
  44. Args:
  45. destination (str): The host name of the remote home server we want
  46. to get the state from.
  47. event_id (str): The id of the event being requested.
  48. timeout (int): How long to try (in ms) the destination for before
  49. giving up. None indicates no timeout.
  50. Returns:
  51. Deferred: Results in a dict received from the remote homeserver.
  52. """
  53. logger.debug("get_pdu dest=%s, event_id=%s",
  54. destination, event_id)
  55. path = PREFIX + "/event/%s/" % (event_id, )
  56. return self.client.get_json(destination, path=path, timeout=timeout)
  57. @log_function
  58. def backfill(self, destination, room_id, event_tuples, limit):
  59. """ Requests `limit` previous PDUs in a given context before list of
  60. PDUs.
  61. Args:
  62. dest (str)
  63. room_id (str)
  64. event_tuples (list)
  65. limt (int)
  66. Returns:
  67. Deferred: Results in a dict received from the remote homeserver.
  68. """
  69. logger.debug(
  70. "backfill dest=%s, room_id=%s, event_tuples=%s, limit=%s",
  71. destination, room_id, repr(event_tuples), str(limit)
  72. )
  73. if not event_tuples:
  74. # TODO: raise?
  75. return
  76. path = PREFIX + "/backfill/%s/" % (room_id,)
  77. args = {
  78. "v": event_tuples,
  79. "limit": [str(limit)],
  80. }
  81. return self.client.get_json(
  82. destination,
  83. path=path,
  84. args=args,
  85. )
  86. @defer.inlineCallbacks
  87. @log_function
  88. def send_transaction(self, transaction, json_data_callback=None):
  89. """ Sends the given Transaction to its destination
  90. Args:
  91. transaction (Transaction)
  92. Returns:
  93. Deferred: Results of the deferred is a tuple in the form of
  94. (response_code, response_body) where the response_body is a
  95. python dict decoded from json
  96. """
  97. logger.debug(
  98. "send_data dest=%s, txid=%s",
  99. transaction.destination, transaction.transaction_id
  100. )
  101. if transaction.destination == self.server_name:
  102. raise RuntimeError("Transport layer cannot send to itself!")
  103. # FIXME: This is only used by the tests. The actual json sent is
  104. # generated by the json_data_callback.
  105. json_data = transaction.get_dict()
  106. response = yield self.client.put_json(
  107. transaction.destination,
  108. path=PREFIX + "/send/%s/" % transaction.transaction_id,
  109. data=json_data,
  110. json_data_callback=json_data_callback,
  111. )
  112. logger.debug(
  113. "send_data dest=%s, txid=%s, got response: 200",
  114. transaction.destination, transaction.transaction_id,
  115. )
  116. defer.returnValue(response)
  117. @defer.inlineCallbacks
  118. @log_function
  119. def make_query(self, destination, query_type, args, retry_on_dns_fail):
  120. path = PREFIX + "/query/%s" % query_type
  121. content = yield self.client.get_json(
  122. destination=destination,
  123. path=path,
  124. args=args,
  125. retry_on_dns_fail=retry_on_dns_fail,
  126. )
  127. defer.returnValue(content)
  128. @defer.inlineCallbacks
  129. @log_function
  130. def make_membership_event(self, destination, room_id, user_id, membership, args={}):
  131. valid_memberships = {Membership.JOIN, Membership.LEAVE}
  132. if membership not in valid_memberships:
  133. raise RuntimeError(
  134. "make_membership_event called with membership='%s', must be one of %s" %
  135. (membership, ",".join(valid_memberships))
  136. )
  137. path = PREFIX + "/make_%s/%s/%s" % (membership, room_id, user_id)
  138. content = yield self.client.get_json(
  139. destination=destination,
  140. path=path,
  141. args=args,
  142. retry_on_dns_fail=True,
  143. )
  144. defer.returnValue(content)
  145. @defer.inlineCallbacks
  146. @log_function
  147. def send_join(self, destination, room_id, event_id, content):
  148. path = PREFIX + "/send_join/%s/%s" % (room_id, event_id)
  149. response = yield self.client.put_json(
  150. destination=destination,
  151. path=path,
  152. data=content,
  153. )
  154. defer.returnValue(response)
  155. @defer.inlineCallbacks
  156. @log_function
  157. def send_leave(self, destination, room_id, event_id, content):
  158. path = PREFIX + "/send_leave/%s/%s" % (room_id, event_id)
  159. response = yield self.client.put_json(
  160. destination=destination,
  161. path=path,
  162. data=content,
  163. )
  164. defer.returnValue(response)
  165. @defer.inlineCallbacks
  166. @log_function
  167. def send_invite(self, destination, room_id, event_id, content):
  168. path = PREFIX + "/invite/%s/%s" % (room_id, event_id)
  169. response = yield self.client.put_json(
  170. destination=destination,
  171. path=path,
  172. data=content,
  173. )
  174. defer.returnValue(response)
  175. @defer.inlineCallbacks
  176. @log_function
  177. def get_event_auth(self, destination, room_id, event_id):
  178. path = PREFIX + "/event_auth/%s/%s" % (room_id, event_id)
  179. content = yield self.client.get_json(
  180. destination=destination,
  181. path=path,
  182. )
  183. defer.returnValue(content)
  184. @defer.inlineCallbacks
  185. @log_function
  186. def send_query_auth(self, destination, room_id, event_id, content):
  187. path = PREFIX + "/query_auth/%s/%s" % (room_id, event_id)
  188. content = yield self.client.post_json(
  189. destination=destination,
  190. path=path,
  191. data=content,
  192. )
  193. defer.returnValue(content)
  194. @defer.inlineCallbacks
  195. @log_function
  196. def query_client_keys(self, destination, query_content):
  197. """Query the device keys for a list of user ids hosted on a remote
  198. server.
  199. Request:
  200. {
  201. "device_keys": {
  202. "<user_id>": ["<device_id>"]
  203. } }
  204. Response:
  205. {
  206. "device_keys": {
  207. "<user_id>": {
  208. "<device_id>": {...}
  209. } } }
  210. Args:
  211. destination(str): The server to query.
  212. query_content(dict): The user ids to query.
  213. Returns:
  214. A dict containg the device keys.
  215. """
  216. path = PREFIX + "/user/keys/query"
  217. content = yield self.client.post_json(
  218. destination=destination,
  219. path=path,
  220. data=query_content,
  221. )
  222. defer.returnValue(content)
  223. @defer.inlineCallbacks
  224. @log_function
  225. def claim_client_keys(self, destination, query_content):
  226. """Claim one-time keys for a list of devices hosted on a remote server.
  227. Request:
  228. {
  229. "one_time_keys": {
  230. "<user_id>": {
  231. "<device_id>": "<algorithm>"
  232. } } }
  233. Response:
  234. {
  235. "device_keys": {
  236. "<user_id>": {
  237. "<device_id>": {
  238. "<algorithm>:<key_id>": "<key_base64>"
  239. } } } }
  240. Args:
  241. destination(str): The server to query.
  242. query_content(dict): The user ids to query.
  243. Returns:
  244. A dict containg the one-time keys.
  245. """
  246. path = PREFIX + "/user/keys/claim"
  247. content = yield self.client.post_json(
  248. destination=destination,
  249. path=path,
  250. data=query_content,
  251. )
  252. defer.returnValue(content)
  253. @defer.inlineCallbacks
  254. @log_function
  255. def get_missing_events(self, destination, room_id, earliest_events,
  256. latest_events, limit, min_depth):
  257. path = PREFIX + "/get_missing_events/%s" % (room_id,)
  258. content = yield self.client.post_json(
  259. destination=destination,
  260. path=path,
  261. data={
  262. "limit": int(limit),
  263. "min_depth": int(min_depth),
  264. "earliest_events": earliest_events,
  265. "latest_events": latest_events,
  266. }
  267. )
  268. defer.returnValue(content)