Skip to content

Commit

Permalink
Process Downloads really on media DCs, including for the main dc_id (fix
Browse files Browse the repository at this point in the history
  • Loading branch information
wiz0u committed Jul 20, 2024
1 parent f7b3a56 commit 9712233
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 10 deletions.
4 changes: 2 additions & 2 deletions src/Client.Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ public async Task<string> DownloadFileAsync(Document document, Stream outputStre
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;
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);
bool canSeek = outputStream.CanSeek;
long streamStartPos = canSeek ? outputStream.Position : 0;
Expand Down Expand Up @@ -347,7 +347,7 @@ async Task<int> LoadPart(long offset)
}
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);
}
catch (RpcException ex) when (ex.Code == 400 && ex.Message == "OFFSET_INVALID")
Expand Down
28 changes: 20 additions & 8 deletions src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,31 +240,43 @@ public void Reset(bool resetUser = true, bool resetSessions = true)

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)
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
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;
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}");
dcSession ??= new Session.DCSession { Id = Helpers.RandomLong() }; // create new session only if not already existing
dcSession.DataCenter = dcOption;
return _session.DCSessions[dcId] = dcSession;
}

/// <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="media_only">Session will be used only for transferring media</param>
/// <param name="dcId">ID of the Data Center (use negative values for media_only)</param>
/// <param name="connect">Connect immediately</param>
/// <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;
Session.DCSession altSession;
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; }
altSession.Client ??= new Client(this, altSession);
}
Expand All @@ -276,7 +288,7 @@ public async Task<Client> GetClientForDC(int dcId, bool media_only = true, bool
{
Auth_ExportedAuthorization exported = null;
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();
if (exported != null)
{
Expand Down

0 comments on commit 9712233

Please sign in to comment.