Process Downloads really on media DCs, including for the main dc_id (fix #261)

This commit is contained in:
Wizou 2024-07-20 02:13:56 +02:00
parent f7b3a56ce3
commit 9712233c00
2 changed files with 22 additions and 10 deletions

View file

@ -314,7 +314,7 @@ namespace WTelegram
public async Task<Storage_FileType> DownloadFileAsync(InputFileLocationBase fileLocation, Stream outputStream, int dc_id = 0, long fileSize = 0, ProgressCallback progress = null) public async Task<Storage_FileType> DownloadFileAsync(InputFileLocationBase fileLocation, Stream outputStream, int dc_id = 0, long fileSize = 0, ProgressCallback progress = null)
{ {
Storage_FileType fileType = Storage_FileType.unknown; Storage_FileType fileType = Storage_FileType.unknown;
var client = dc_id == 0 ? this : await GetClientForDC(dc_id, true); var client = dc_id == 0 ? this : await GetClientForDC(-dc_id, true);
using var writeSem = new SemaphoreSlim(1); using var writeSem = new SemaphoreSlim(1);
bool canSeek = outputStream.CanSeek; bool canSeek = outputStream.CanSeek;
long streamStartPos = canSeek ? outputStream.Position : 0; long streamStartPos = canSeek ? outputStream.Position : 0;
@ -347,7 +347,7 @@ namespace WTelegram
} }
catch (RpcException ex) when (ex.Code == 303 && ex.Message == "FILE_MIGRATE_X") catch (RpcException ex) when (ex.Code == 303 && ex.Message == "FILE_MIGRATE_X")
{ {
client = await GetClientForDC(ex.X, true); client = await GetClientForDC(-ex.X, true);
fileBase = await client.Upload_GetFile(fileLocation, offset, FilePartSize); fileBase = await client.Upload_GetFile(fileLocation, offset, FilePartSize);
} }
catch (RpcException ex) when (ex.Code == 400 && ex.Message == "OFFSET_INVALID") catch (RpcException ex) when (ex.Code == 400 && ex.Message == "OFFSET_INVALID")

View file

@ -240,13 +240,24 @@ namespace WTelegram
private Session.DCSession GetOrCreateDCSession(int dcId, DcOption.Flags flags) private Session.DCSession GetOrCreateDCSession(int dcId, DcOption.Flags flags)
{ {
if (_session.DCSessions.TryGetValue(dcId, out var dcSession)) if (_session.DCSessions.TryGetValue(dcId, out var dcSession) && dcSession.AuthKey != null)
if (dcSession.Client != null || dcSession.DataCenter.flags == flags) if (dcSession.Client != null || dcSession.DataCenter.flags == flags)
return dcSession; // if we have already a session with this DC and we are connected or it is a perfect match, use it return dcSession; // if we have already a session with this DC and we are connected or it is a perfect match, use it
if (dcSession == null && _session.DCSessions.TryGetValue(-dcId, out dcSession) && dcSession.AuthKey != null)
{
if (dcSession.DataCenter.flags == flags && _session.DCSessions.Remove(-dcId))
return _session.DCSessions[dcId] = dcSession; // we found a misclassed DC, change its sign
dcSession = new Session.DCSession { Id = Helpers.RandomLong(), // clone AuthKey for a session on the matching media_only DC
AuthKeyID = dcSession.AuthKeyID, AuthKey = dcSession.AuthKey, UserId = dcSession.UserId };
}
// try to find the most appropriate DcOption for this DC // try to find the most appropriate DcOption for this DC
if ((dcSession?.AuthKeyID ?? 0) == 0) // we will need to negociate an AuthKey => can't use media_only DC if (dcSession?.AuthKey == null) // we'll need to negociate an AuthKey => can't use media_only DC
{
flags &= ~DcOption.Flags.media_only; flags &= ~DcOption.Flags.media_only;
var dcOptions = _session.DcOptions.Where(dc => dc.id == dcId).OrderBy(dc => dc.flags ^ flags); dcId = Math.Abs(dcId);
}
var dcOptions = _session.DcOptions.Where(dc => dc.id == Math.Abs(dcId))
.OrderBy(dc => dc.flags.HasFlag(DcOption.Flags.media_only) ^ (dcId < 0)).ThenBy(dc => dc.flags ^ flags);
var dcOption = dcOptions.FirstOrDefault() ?? throw new WTException($"Could not find adequate dc_option for DC {dcId}"); var dcOption = dcOptions.FirstOrDefault() ?? throw new WTException($"Could not find adequate dc_option for DC {dcId}");
dcSession ??= new Session.DCSession { Id = Helpers.RandomLong() }; // create new session only if not already existing dcSession ??= new Session.DCSession { Id = Helpers.RandomLong() }; // create new session only if not already existing
dcSession.DataCenter = dcOption; dcSession.DataCenter = dcOption;
@ -254,17 +265,18 @@ namespace WTelegram
} }
/// <summary>Obtain/create a Client for a secondary session on a specific Data Center</summary> /// <summary>Obtain/create a Client for a secondary session on a specific Data Center</summary>
/// <param name="dcId">ID of the Data Center</param> /// <param name="dcId">ID of the Data Center (use negative values for media_only)</param>
/// <param name="media_only">Session will be used only for transferring media</param>
/// <param name="connect">Connect immediately</param> /// <param name="connect">Connect immediately</param>
/// <returns>Client connected to the selected DC</returns> /// <returns>Client connected to the selected DC</returns>
public async Task<Client> GetClientForDC(int dcId, bool media_only = true, bool connect = true) public async Task<Client> GetClientForDC(int dcId, bool connect = true)
{ {
if (_dcSession.DataCenter?.id == dcId) return this; if (_dcSession.DataCenter?.id == dcId) return this;
Session.DCSession altSession; Session.DCSession altSession;
lock (_session) lock (_session)
{ {
altSession = GetOrCreateDCSession(dcId, _dcSession.DataCenter.flags | (media_only ? DcOption.Flags.media_only : 0)); var flags = _dcSession.DataCenter.flags;
if (dcId < 0) flags = (flags & DcOption.Flags.ipv6) | DcOption.Flags.media_only;
altSession = GetOrCreateDCSession(dcId, flags);
if (altSession.Client?.Disconnected ?? false) { altSession.Client.Dispose(); altSession.Client = null; } if (altSession.Client?.Disconnected ?? false) { altSession.Client.Dispose(); altSession.Client = null; }
altSession.Client ??= new Client(this, altSession); altSession.Client ??= new Client(this, altSession);
} }
@ -276,7 +288,7 @@ namespace WTelegram
{ {
Auth_ExportedAuthorization exported = null; Auth_ExportedAuthorization exported = null;
if (_session.UserId != 0 && IsMainDC && altSession.UserId != _session.UserId) if (_session.UserId != 0 && IsMainDC && altSession.UserId != _session.UserId)
exported = await this.Auth_ExportAuthorization(dcId); exported = await this.Auth_ExportAuthorization(Math.Abs(dcId));
await altSession.Client.ConnectAsync(); await altSession.Client.ConnectAsync();
if (exported != null) if (exported != null)
{ {