diff --git a/.github/dev.yml b/.github/dev.yml index 5c587f8..e3453ef 100644 --- a/.github/dev.yml +++ b/.github/dev.yml @@ -2,7 +2,7 @@ pr: none trigger: - master -name: 2.2.2-dev.$(Rev:r) +name: 2.3.1-dev.$(Rev:r) pool: vmImage: ubuntu-latest diff --git a/.github/release.yml b/.github/release.yml index 0b36981..215fda7 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -1,7 +1,7 @@ pr: none trigger: none -name: 2.2.$(Rev:r) +name: 2.3.$(Rev:r) pool: vmImage: ubuntu-latest diff --git a/src/Client.Helpers.cs b/src/Client.Helpers.cs index b8877d6..d8690c5 100644 --- a/src/Client.Helpers.cs +++ b/src/Client.Helpers.cs @@ -362,10 +362,9 @@ namespace WTelegram { fileBase = await client.Upload_GetFile(fileLocation, offset, FilePartSize); } - catch (RpcException ex) when (ex.Code == 303 && ex.Message.StartsWith("FILE_MIGRATE_")) + catch (RpcException ex) when (ex.Code == 303 && ex.Message == "FILE_MIGRATE_X") { - var dcId = int.Parse(ex.Message[13..]); - client = await GetClientForDC(dcId, 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") diff --git a/src/Client.cs b/src/Client.cs index 0d690ca..35d05d0 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -1088,41 +1088,40 @@ namespace WTelegram } } - internal async Task InvokeBare(IMethod request) + internal async Task InvokeBare(IMethod request) { if (_bareRpc != null) throw new ApplicationException("A bare request is already undergoing"); - _bareRpc = new Rpc { type = typeof(X) }; + _bareRpc = new Rpc { type = typeof(T) }; await SendAsync(request, false, _bareRpc); - return (X)await _bareRpc.Task; + return (T)await _bareRpc.Task; } /// Call the given TL method (You shouldn't need to use this method directly) - /// Expected type of the returned object + /// Expected type of the returned object /// TL method structure /// Wait for the reply and return the resulting object, or throws an RpcException if an error was replied - public async Task Invoke(IMethod query) + public async Task Invoke(IMethod query) { - retry: - var rpc = new Rpc { type = typeof(X) }; - await SendAsync(query, true, rpc); bool got503 = false; + retry: + var rpc = new Rpc { type = typeof(T) }; + await SendAsync(query, true, rpc); var result = await rpc.Task; switch (result) { - case X resultX: return resultX; + case T resultT: return resultT; case RpcError rpcError: - int number; - if (rpcError.error_code == 303 && ((number = rpcError.error_message.IndexOf("_MIGRATE_")) > 0)) + var x = rpcError.ParseX(); + if (rpcError.error_code == 303 && rpcError.error_message.EndsWith("_MIGRATE_X")) { - if (!rpcError.error_message.StartsWith("FILE_")) + if (rpcError.error_message != "FILE_MIGRATE_X") { - number = int.Parse(rpcError.error_message[(number + 9)..]); // this is a hack to migrate _dcSession in-place (staying in same Client): Session.DCSession dcSession; lock (_session) - dcSession = GetOrCreateDCSession(number, _dcSession.DataCenter.flags); + dcSession = GetOrCreateDCSession(x, _dcSession.DataCenter.flags); Reset(false, false); - _session.MainDC = number; + _session.MainDC = x; _dcSession.Client = null; _dcSession = dcSession; _dcSession.Client = this; @@ -1130,12 +1129,11 @@ namespace WTelegram goto retry; } } - else if (rpcError.error_code == 420 && ((number = rpcError.error_message.IndexOf("_WAIT_")) > 0)) + else if (rpcError.error_code == 420 && rpcError.error_message.EndsWith("_WAIT_X")) { - number = int.Parse(rpcError.error_message[(number + 6)..]); - if (number <= FloodRetryThreshold) + if (x <= FloodRetryThreshold) { - await Task.Delay(number * 1000); + await Task.Delay(x * 1000); goto retry; } } @@ -1149,11 +1147,11 @@ namespace WTelegram _session.UserId = 0; // force a full login authorization flow, next time lock (_session) _session.Save(); } - throw new RpcException(rpcError.error_code, rpcError.error_message); + throw new RpcException(rpcError.error_code, rpcError.error_message, x); case ReactorError: goto retry; default: - throw new ApplicationException($"{query.GetType().Name} call got a result of type {result.GetType().Name} instead of {typeof(X).Name}"); + throw new ApplicationException($"{query.GetType().Name} call got a result of type {result.GetType().Name} instead of {typeof(T).Name}"); } } } diff --git a/src/TL.Extensions.cs b/src/TL.Extensions.cs index bdc9434..05731d5 100644 --- a/src/TL.Extensions.cs +++ b/src/TL.Extensions.cs @@ -32,8 +32,6 @@ namespace TL /// Accumulate users/chats found in this structure in your dictionaries, ignoring Min constructors when the full object is already stored /// The structure having a users - /// - /// public static void CollectUsersChats(this IPeerResolver structure, Dictionary users, Dictionary chats) => structure.UserOrChat(new CollectorPeer { _users = users, _chats = chats }); } diff --git a/src/TL.MTProto.cs b/src/TL.MTProto.cs index e05fe98..45ef72d 100644 --- a/src/TL.MTProto.cs +++ b/src/TL.MTProto.cs @@ -198,6 +198,22 @@ namespace TL { public int error_code; public string error_message; + + public int ParseX() // ⚠ Method replace number in error_message with a X + { + for (int index = error_message.Length - 1; index > 0 && (index = error_message.LastIndexOf('_', index - 1)) >= 0;) + { + if (error_message[index + 1] is >= '0' and <= '9') + { + int end = ++index; + do end++; while (end < error_message.Length && error_message[end] is >= '0' and <= '9'); + var x = int.Parse(error_message[index..end]); + error_message = $"{error_message[0..index]}X{error_message[end..]}"; + return x; + } + } + return -1; + } } public abstract class RpcDropAnswer : IObject { } diff --git a/src/TL.cs b/src/TL.cs index a4e09b3..83118ac 100644 --- a/src/TL.cs +++ b/src/TL.cs @@ -31,7 +31,9 @@ namespace TL public class RpcException : Exception { public readonly int Code; - public RpcException(int code, string message) : base(message) => Code = code; + /// The value of X in the message, -1 if no variable X was found + public readonly int X; + public RpcException(int code, string message, int x = -1) : base(message) { Code = code; X = x; } public override string ToString() { var str = base.ToString(); return str.Insert(str.IndexOf(':') + 1, " " + Code); } }