@@ -381,10 +381,8 @@ def __init__(
381381 self .business_connections = {}
382382
383383 self .sessions = {}
384- self .sessions_lock = asyncio .Lock ()
385-
386384 self .media_sessions = {}
387- self .media_sessions_lock = asyncio .Lock ()
385+ self .sessions_lock = asyncio .Lock ()
388386
389387 self .save_file_semaphore = asyncio .Semaphore (self .max_concurrent_transmissions )
390388 self .get_file_semaphore = asyncio .Semaphore (self .max_concurrent_transmissions )
@@ -416,6 +414,8 @@ def __init__(
416414 else :
417415 self .loop = asyncio .get_event_loop ()
418416
417+ self .__config = None
418+
419419 def __enter__ (self ):
420420 return self .start ()
421421
@@ -898,12 +898,17 @@ async def load_session(self):
898898 await self .storage .api_id (self .api_id )
899899
900900 await self .storage .dc_id (2 )
901+ await self .storage .server_address ("149.154.167.51" )
902+ await self .storage .port (443 )
901903 await self .storage .date (0 )
902904
903905 await self .storage .test_mode (self .test_mode )
904906 await self .storage .auth_key (
905907 await Auth (
906- self , await self .storage .dc_id (),
908+ self ,
909+ await self .storage .dc_id (),
910+ await self .storage .server_address (),
911+ await self .storage .port (),
907912 await self .storage .test_mode ()
908913 ).create ()
909914 )
@@ -1136,10 +1141,20 @@ async def get_file(
11361141 try :
11371142 session = self .media_sessions .get (dc_id )
11381143 if not session :
1144+ dc_option = await self .get_dc_option (dc_id , is_media = True , ipv6 = self .ipv6 )
1145+
11391146 session = self .media_sessions [dc_id ] = Session (
1140- self , dc_id ,
1141- await Auth (self , dc_id , await self .storage .test_mode ()).create ()
1142- if dc_id != await self .storage .dc_id ()
1147+ self ,
1148+ dc_id ,
1149+ dc_option .ip_address ,
1150+ dc_option .port ,
1151+ await Auth (
1152+ self ,
1153+ dc_id ,
1154+ dc_option .ip_address ,
1155+ dc_option .port ,
1156+ await self .storage .test_mode ()
1157+ ).create () if dc_id != await self .storage .dc_id ()
11431158 else await self .storage .auth_key (),
11441159 await self .storage .test_mode (),
11451160 is_media = True
@@ -1214,9 +1229,23 @@ async def get_file(
12141229 )
12151230
12161231 elif isinstance (r , raw .types .upload .FileCdnRedirect ):
1232+ dc_option = await self .get_dc_option (dc_id , is_cdn = True , ipv6 = self .ipv6 )
1233+
12171234 cdn_session = Session (
1218- self , r .dc_id , await Auth (self , r .dc_id , await self .storage .test_mode ()).create (),
1219- await self .storage .test_mode (), is_media = True , is_cdn = True
1235+ self ,
1236+ r .dc_id ,
1237+ dc_option .ip_address ,
1238+ dc_option .port ,
1239+ await Auth (
1240+ self ,
1241+ r .dc_id ,
1242+ dc_option .ip_address ,
1243+ dc_option .port ,
1244+ await self .storage .test_mode ()
1245+ ).create (),
1246+ await self .storage .test_mode (),
1247+ is_media = True ,
1248+ is_cdn = True
12201249 )
12211250
12221251 try :
@@ -1302,6 +1331,186 @@ async def get_file(
13021331 except Exception as e :
13031332 log .exception (e )
13041333
1334+ async def get_session (
1335+ self ,
1336+ dc_id : int ,
1337+ is_media : Optional [bool ] = False ,
1338+ export_authorization : Optional [bool ] = True ,
1339+ server_address : Optional [str ] = None ,
1340+ port : Optional [int ] = None
1341+ ) -> "Session" :
1342+ """Get existing session or create a new one.
1343+
1344+ Parameters:
1345+ dc_id (``int``):
1346+ Datacenter identifier.
1347+
1348+ is_media (``bool``, *optional*):
1349+ Pass True to get or create a media session.
1350+
1351+ export_authorization (``bool``, *optional*):
1352+ Pass True to export authorization after creating the session.
1353+ Used only when creating a new session.
1354+
1355+ server_address (``str``, *optional*):
1356+ Custom server address to connect to.
1357+ Used only when creating a new session.
1358+
1359+ port (``int``, *optional*):
1360+ Custom port to connect to.
1361+ Used only when creating a new session.
1362+ """
1363+ if dc_id == await self .storage .dc_id ():
1364+ return self .session
1365+
1366+ sessions = self .media_sessions if is_media else self .sessions
1367+
1368+ async with self .sessions_lock :
1369+ if sessions .get (dc_id ):
1370+ return sessions [dc_id ]
1371+
1372+ dc_option = await self .get_dc_option (dc_id , is_media = is_media , ipv6 = self .ipv6 )
1373+
1374+ session = self .media_sessions [dc_id ] = Session (
1375+ self ,
1376+ dc_id ,
1377+ server_address or dc_option .ip_address ,
1378+ port or dc_option .port ,
1379+ await Auth (
1380+ self ,
1381+ dc_id ,
1382+ server_address or dc_option .ip_address ,
1383+ port or dc_option .port ,
1384+ await self .storage .test_mode ()
1385+ ).create (),
1386+ await self .storage .test_mode (), is_media = is_media
1387+ )
1388+
1389+ await session .start ()
1390+
1391+ if export_authorization :
1392+ for _ in range (3 ):
1393+ exported_auth = await self .invoke (
1394+ raw .functions .auth .ExportAuthorization (
1395+ dc_id = dc_id
1396+ )
1397+ )
1398+
1399+ try :
1400+ await session .invoke (
1401+ raw .functions .auth .ImportAuthorization (
1402+ id = exported_auth .id ,
1403+ bytes = exported_auth .bytes
1404+ )
1405+ )
1406+ except AuthBytesInvalid :
1407+ continue
1408+ else :
1409+ break
1410+ else :
1411+ await session .stop ()
1412+ raise AuthBytesInvalid
1413+
1414+ return session
1415+
1416+ async def get_dc_option (
1417+ self ,
1418+ dc_id : int ,
1419+ is_media : bool = False ,
1420+ is_cdn : bool = False ,
1421+ ipv6 : bool = False
1422+ ) -> "raw.types.DcOption" :
1423+ if not self .__config :
1424+ self .__config = await self .invoke (raw .functions .help .GetConfig ())
1425+
1426+ options = [dc for dc in self .__config .dc_options if dc .id == dc_id and dc .ipv6 == ipv6 ] # type: List[raw.types.DcOption]
1427+
1428+ if not options :
1429+ raise ValueError (f"DC{ dc_id } not found" )
1430+
1431+ if is_cdn :
1432+ cdn_options = [dc for dc in options if dc .cdn ]
1433+
1434+ if cdn_options :
1435+ return cdn_options [0 ]
1436+
1437+ log .debug (
1438+ "No CDN datacenter found for DC%s, falling back to prod DC" ,
1439+ dc_id
1440+ )
1441+
1442+ is_media = True
1443+
1444+ if is_media :
1445+ media_options = [dc for dc in options if dc .media_only ]
1446+
1447+ if media_options :
1448+ return media_options [0 ]
1449+
1450+ log .debug (
1451+ "No media datacenter found for DC%s, falling back to prod DC" ,
1452+ dc_id
1453+ )
1454+
1455+ prod_options = [dc for dc in options if not dc .media_only ]
1456+
1457+ if prod_options :
1458+ return prod_options [0 ]
1459+
1460+ raise ValueError ("No suitable DC found" )
1461+
1462+ async def set_dc (
1463+ self ,
1464+ dc_id : Optional [int ] = None ,
1465+ * ,
1466+ server_address : Optional [str ] = None ,
1467+ port : Optional [int ] = None
1468+ ):
1469+ """Be careful with this method, you can easily break your session."""
1470+ if not self .__config :
1471+ self .__config = await self .invoke (raw .functions .help .GetConfig ())
1472+
1473+ dc_id = dc_id or self .__config .this_dc
1474+
1475+ dc_option = await self .get_dc_option (dc_id , ipv6 = self .ipv6 )
1476+
1477+ server_address = server_address or dc_option .ip_address
1478+ port = port or dc_option .port
1479+
1480+ if dc_id == self .__config .this_dc and (self .session .server_address != server_address or self .session .port != port ):
1481+ await self .storage .server_address (server_address )
1482+ await self .storage .port (port )
1483+
1484+ self .session .server_address = await self .storage .server_address ()
1485+ self .session .port = await self .storage .port ()
1486+
1487+ await self .session .restart ()
1488+ log .info ("Changed the current session DC%s address to %s:%s" , dc_id , server_address , port )
1489+ else :
1490+ prod_session = self .sessions .get (dc_id )
1491+
1492+ if prod_session and (prod_session .server_address != server_address or prod_session .port != port ):
1493+ prod_session .server_address = server_address
1494+ prod_session .port = port
1495+
1496+ await prod_session .restart ()
1497+ log .info ("Changed session DC%s address to %s:%s" , dc_id , server_address , port )
1498+ else :
1499+ await self .get_session (dc_id , server_address = server_address , port = port )
1500+ log .info ("Created new session DC%s with address %s:%s" , dc_id , server_address , port )
1501+
1502+ media_session = self .media_sessions .get (dc_id )
1503+
1504+ if media_session and (media_session .server_address != server_address or media_session .port != port ):
1505+ media_session .server_address = server_address
1506+ media_session .port = port
1507+
1508+ await media_session .restart ()
1509+ log .info ("Changed session DC%s (media) address to %s:%s" , dc_id , server_address , port )
1510+ else :
1511+ await self .get_session (dc_id , is_media = True , server_address = server_address , port = port )
1512+ log .info ("Created new session DC%s (media) with address %s:%s" , dc_id , server_address , port )
1513+
13051514 def guess_mime_type (self , filename : Union [str , BytesIO ]) -> Optional [str ]:
13061515 if isinstance (filename , BytesIO ):
13071516 return self .mimetypes .guess_type (filename .name )[0 ]
0 commit comments