@@ -28,7 +28,8 @@ def quote(*args, **kwargs):
2828class HTTPAPI :
2929 def __init__ (self , base_url : str , domain : str = None , bot_mxid : str = None , token : str = None ,
3030 identity : str = None , log : Logger = None , state_store : StateStore = None ,
31- client_session : ClientSession = None , child : bool = False ):
31+ client_session : ClientSession = None , child : bool = False , real_user : bool = False ,
32+ real_user_content_key : Optional [str ] = None ):
3233 self .base_url = base_url
3334 self .token = token
3435 self .identity = identity
@@ -39,14 +40,17 @@ def __init__(self, base_url: str, domain: str = None, bot_mxid: str = None, toke
3940 self .bot_mxid = bot_mxid
4041 self ._bot_intent = None
4142 self .state_store = state_store
43+ self .is_real_user = real_user
44+ self .real_user_content_key = real_user_content_key
4245
43- if child :
46+ if child or real_user :
4447 self .log = log
4548 else :
4649 self .intent_log = log .getChild ("intent" )
4750 self .log = log .getChild ("api" )
4851 self .txn_id = 0
4952 self .children = {}
53+ self .real_users = {}
5054
5155 def user (self , user : str ) -> "ChildHTTPAPI" :
5256 """
@@ -58,25 +62,42 @@ def user(self, user: str) -> "ChildHTTPAPI":
5862 Returns:
5963 A HTTPAPI instance that always uses the given Matrix ID.
6064 """
65+ if self .is_real_user :
66+ raise ValueError ("Can't get child of real user" )
67+
6168 try :
6269 return self .children [user ]
6370 except KeyError :
6471 child = ChildHTTPAPI (user , self )
6572 self .children [user ] = child
6673 return child
6774
75+ def real_user (self , mxid : str , token : str ) -> "HTTPAPI" :
76+ if self .is_real_user :
77+ raise ValueError ("Can't get child of real user" )
78+
79+ try :
80+ return self .real_users [mxid ]
81+ except KeyError :
82+ child = self .__class__ (self .base_url , self .domain , None , token , mxid , self .log ,
83+ self .state_store , self .session , real_user = True ,
84+ real_user_content_key = self .real_user_content_key )
85+ self .real_users [mxid ] = child
86+ return child
87+
6888 def bot_intent (self ) -> "IntentAPI" :
6989 """
7090 Get the intent API for the appservice bot.
7191
7292 Returns:
7393 The IntentAPI for the appservice bot.
7494 """
75- if self ._bot_intent :
76- return self ._bot_intent
77- return IntentAPI (self .bot_mxid , self , state_store = self .state_store , log = self .intent_log )
95+ if not self ._bot_intent :
96+ self ._bot_intent = IntentAPI (self .bot_mxid , self , state_store = self .state_store ,
97+ log = self .intent_log )
98+ return self ._bot_intent
7899
79- def intent (self , user : str ) -> "IntentAPI" :
100+ def intent (self , user : str = None , token : Optional [ str ] = None ) -> "IntentAPI" :
80101 """
81102 Get the intent API for a specific user.
82103
@@ -86,6 +107,11 @@ def intent(self, user: str) -> "IntentAPI":
86107 Returns:
87108 The IntentAPI for the given user.
88109 """
110+ if self .is_real_user :
111+ raise ValueError ("Can't get child intent of real user" )
112+ if token :
113+ return IntentAPI (user , self .real_user (user , token ), self .bot_intent (), self .state_store ,
114+ self .intent_log )
89115 return IntentAPI (user , self .user (user ), self .bot_intent (), self .state_store ,
90116 self .intent_log )
91117
@@ -154,19 +180,50 @@ def request(self, method: str, path: str, content: Optional[Union[dict, bytes, s
154180 if method not in ["GET" , "PUT" , "DELETE" , "POST" ]:
155181 raise MatrixError ("Unsupported HTTP method: %s" % method )
156182
157- if "Content-Type" not in headers :
183+ if content and "Content-Type" not in headers :
158184 headers ["Content-Type" ] = "application/json"
159- if headers [ "Content-Type" ] == "application/json" :
185+ if headers . get ( "Content-Type" , None ) == "application/json" :
160186 content = json .dumps (content )
161187
162- if self .identity :
188+ if self .identity and not self . is_real_user :
163189 query_params ["user_id" ] = self .identity
164190
165191 self ._log_request (method , path , content , query_params )
166192
167193 endpoint = self .base_url + api_path + path
168194 return self ._send (method , endpoint , content , query_params , headers or {})
169195
196+ def sync (self , since = None , timeout_ms = 30000 , filter = None , full_state = None , set_presence = None ):
197+ """ Perform a sync request.
198+ Args:
199+ since (str): Optional. A token which specifies where to continue a sync from.
200+ timeout_ms (int): Optional. The time in m1illiseconds to wait.
201+ filter (int|str): Either a Filter ID or a JSON string.
202+ full_state (bool): Return the full state for every room the user has joined
203+ Defaults to false.
204+ set_presence (str): Should the client be marked as "online" or" offline"
205+ """
206+ request = {
207+ "timeout" : int (timeout_ms )
208+ }
209+
210+ if since :
211+ request ["since" ] = since
212+ if filter :
213+ request ["filter" ] = filter
214+ if full_state :
215+ request ["full_state" ] = json .dumps (full_state )
216+ if set_presence :
217+ request ["set_presence" ] = set_presence
218+ return self .request ("GET" , "/sync" , query_params = request )
219+
220+ def get_filter (self , user_id : str , filter_id : str ) -> Awaitable [dict ]:
221+ return self .request ("GET" , f"/user/{ user_id } /filter/{ filter_id } " )
222+
223+ async def create_filter (self , user_id : str , filter_params : dict ) -> str :
224+ resp = await self .request ("POST" , f"/user/{ user_id } /filter" , filter_params )
225+ return resp .get ("filter_id" , None )
226+
170227 def get_download_url (self , mxc_uri : str ) -> str :
171228 """
172229 Get the full URL to download a mxc:// URI.
@@ -191,7 +248,8 @@ class ChildHTTPAPI(HTTPAPI):
191248
192249 def __init__ (self , user : str , parent : HTTPAPI ):
193250 super ().__init__ (parent .base_url , parent .domain , parent .bot_mxid , parent .token , user ,
194- parent .log , parent .state_store , parent .session , child = True )
251+ parent .log , parent .state_store , parent .session , child = True ,
252+ real_user_content_key = parent .real_user_content_key )
195253 self .parent = parent
196254
197255 @property
@@ -225,7 +283,7 @@ def __init__(self, mxid: str, client: HTTPAPI, bot: "IntentAPI" = None,
225283
226284 self .state_store = state_store
227285
228- def user (self , user : str ) -> "IntentAPI" :
286+ def user (self , user : str , token : Optional [ str ] = None ) -> "IntentAPI" :
229287 """
230288 Get the intent API for a specific user. This is just a proxy to :func:`~HTTPAPI.intent`.
231289
@@ -234,15 +292,16 @@ def user(self, user: str) -> "IntentAPI":
234292
235293 Args:
236294 user: The Matrix ID of the user whose intent API to get.
295+ token: The access token to use for the Matrix ID.
237296
238297 Returns:
239298 The IntentAPI for the given user.
240299 """
241300 if not self .bot :
242- return self .client .intent (user )
301+ return self .client .intent (user , token )
243302 else :
244303 self .log .warning ("Called IntentAPI#user() of child intent object." )
245- return self .bot .client .intent (user )
304+ return self .bot .client .intent (user , token )
246305
247306 # region User actions
248307
@@ -541,6 +600,16 @@ async def set_join_rule(self, room_id: str, join_rule: str, **kwargs):
541600 "join_rule" : join_rule ,
542601 }, ** kwargs )
543602
603+ async def get_profile (self , user_id : str ) -> dict :
604+ return await self .client .request ("GET" , f"/profile/{ quote (user_id )} " )
605+
606+ async def whoami (self ) -> Optional [str ]:
607+ try :
608+ resp = await self .client .request ("GET" , f"/account/whoami" )
609+ return resp .get ("user_id" , None )
610+ except MatrixError :
611+ return None
612+
544613 async def get_displayname (self , room_id : str , user_id : str , ignore_cache = False ) -> str :
545614 return (await self .get_member_info (room_id , user_id , ignore_cache )).get ("displayname" , None )
546615
@@ -688,6 +757,9 @@ async def send_event(self, room_id: str, event_type: str, content: dict,
688757 await self .ensure_joined (room_id )
689758 await self ._ensure_has_power_level_for (room_id , event_type )
690759
760+ if self .client .is_real_user and self .client .real_user_content_key :
761+ content [self .client .real_user_content_key ] = True
762+
691763 txn_id = txn_id or str (self .client .txn_id ) + str (int (time () * 1000 ))
692764 self .client .txn_id += 1
693765
0 commit comments