diff --git a/src/Client.cs b/src/Client.cs index 2fff57c..06860ea 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -27,7 +27,7 @@ namespace WTelegram private TcpClient _tcpClient; private NetworkStream _networkStream; private int _frame_seqTx = 0, _frame_seqRx = 0; - private ITLFunction _lastSentMsg; + private ITLFunction _lastSentMsg; private Type _lastRpcResultType = typeof(object); private readonly List _msgsToAck = new(); private int _unexpectedSaltChange; @@ -96,8 +96,8 @@ namespace WTelegram if (_session.AuthKey == null) await CreateAuthorizationKey(this, _session); - TLConfig = await InvokeWithLayer(Schema.Layer, - InitConnection(_apiId, + TLConfig = await InvokeWithLayer(Schema.Layer, + InitConnection(_apiId, Config("device_model"), Config("system_version"), Config("app_version"), @@ -140,13 +140,13 @@ namespace WTelegram } public Task SendAsync(ITLObject msg, bool isContent = true) - => SendAsync(writer => + => SendAsync(writer => { writer.WriteTLObject(msg); return msg.GetType().Name; }, isContent); - public async Task SendAsync(ITLFunction msgSerializer, bool isContent = true) + public async Task SendAsync(ITLFunction msgSerializer, bool isContent = true) { if (_session.AuthKeyID != 0) await CheckMsgsToAck(); using var memStream = new MemoryStream(1024); @@ -215,7 +215,7 @@ namespace WTelegram //TODO: support Transport obfuscation? await _networkStream.WriteAsync(frame); - _lastSentMsg = writer => msgSerializer(writer); + _lastSentMsg = msgSerializer; } internal async Task RecvInternalAsync() @@ -239,8 +239,9 @@ namespace WTelegram int length = reader.ReadInt32(); if (length != data.Length - 20) throw new ApplicationException($"Unexpected unencrypted length {length} != {data.Length - 20}"); - return reader.ReadTLObject((type, _) => - Helpers.Log(1, $"Receiving {type.Name,-50} timestamp={_session.MsgIdToStamp(msgId)} isResponse={(msgId & 2) != 0} unencrypted")); + var obj = reader.ReadTLObject(); + Helpers.Log(1, $"Receiving {obj.GetType().Name,-50} timestamp={_session.MsgIdToStamp(msgId)} isResponse={(msgId & 2) != 0} unencrypted"); + return obj; } else if (authKeyId != _session.AuthKeyID) throw new ApplicationException($"Received a packet encrypted with unexpected key {authKeyId:X}"); @@ -282,13 +283,12 @@ namespace WTelegram if (!data.AsSpan(8, 16).SequenceEqual(_sha256.Hash.AsSpan(8, 16))) throw new ApplicationException($"Mismatch between MsgKey & decrypted SHA1"); #endif - return reader.ReadTLObject((type, obj) => - { - Helpers.Log(1, $"Receiving {type.Name,-50} timestamp={_session.MsgIdToStamp(msgId)} isResponse={(msgId & 2) != 0} {(seqno == -1 ? "clearText" : "isContent")}={(seqno & 1) != 0}"); - if (type == typeof(RpcResult)) - DeserializeRpcResult(reader, (RpcResult)obj); // necessary hack because some RPC return bare types like bool or int[] - }); - } + var obj = reader.ReadTLObject(type => type == typeof(RpcResult)); + if (obj is RpcResult rpcResult) + DeserializeRpcResult(reader, rpcResult); // necessary hack because some RPC return bare types like bool or int[] + Helpers.Log(1, $"Receiving {obj.GetType().Name,-50} timestamp={_session.MsgIdToStamp(msgId)} isResponse={(msgId & 2) != 0} {(seqno == -1 ? "clearText" : "isContent")}={(seqno & 1) != 0}"); + return obj; + } static string TransportError(int error_code) => error_code switch { @@ -350,7 +350,7 @@ namespace WTelegram public RpcException(int code, string message) : base(message) => Code = code; } - public async Task CallAsync(ITLFunction request) + public async Task CallAsync(ITLFunction request) { await SendAsync(request); // TODO: create a background reactor system that handles incoming packets and wake up awaiting tasks when their result has arrived diff --git a/src/Generator.cs b/src/Generator.cs index d76c729..7a22a44 100644 --- a/src/Generator.cs +++ b/src/Generator.cs @@ -156,7 +156,7 @@ namespace WTelegram { var parentClass = typeInfo.NeedAbstract != 0 ? typeInfo.ReturnName : "ITLObject"; var genericType = typeInfo.ReturnName.Length == 1 ? $"<{typeInfo.ReturnName}>" : null; - if (isMethod) parentClass = $"ITLFunction<{MapType(typeInfo.ReturnName, "")}>"; + if (isMethod) parentClass = "ITLFunction"; bool needNewLine = true; if (typeInfo.NeedAbstract == -1 && allTypes.Add(layerPrefix + parentClass)) { @@ -293,7 +293,7 @@ namespace WTelegram else if (type == "Object") return "ITLObject"; else if (type == "!X") - return "ITLFunction"; + return "ITLFunction"; else if (typeInfos.TryGetValue(type, out var typeInfo)) return typeInfo.ReturnName; else if (type == "int") @@ -345,7 +345,7 @@ namespace WTelegram if (style == -1) return; sw.WriteLine(); - if (method.type.Length == 1) funcName += $"<{returnType}>"; + if (method.type.Length == 1 && style != 1) funcName += $"<{returnType}>"; if (currentJson != "TL.MTProto") sw.WriteLine($"{tabIndent}///See "); else @@ -358,7 +358,7 @@ namespace WTelegram if (style == 0) sw.WriteLine($"{tabIndent}public Task<{returnType}> {funcName}() => CallAsync<{returnType}>({funcName});"); if (style == 0) sw.Write($"{tabIndent}public static string {funcName}(BinaryWriter writer"); - if (style == 1) sw.Write($"{tabIndent}public static ITLFunction<{returnType}> {funcName}("); + if (style == 1) sw.Write($"{tabIndent}public static ITLFunction {funcName}("); if (style == 2) sw.Write($"{tabIndent}public Task<{returnType}> {funcName}("); bool first = style != 0; foreach (var parm in method.@params) // output non-optional parameters diff --git a/src/TL.Schema.cs b/src/TL.Schema.cs index 096cfa2..746d2c2 100644 --- a/src/TL.Schema.cs +++ b/src/TL.Schema.cs @@ -6209,7 +6209,7 @@ namespace WTelegram // ---functions--- public partial class Client { ///See - public Task InvokeAfterMsg(long msg_id, ITLFunction query) + public Task InvokeAfterMsg(long msg_id, ITLFunction query) => CallAsync(writer => { writer.Write(0xCB9F372D); @@ -6219,7 +6219,7 @@ namespace WTelegram // ---functions--- }); ///See - public Task InvokeAfterMsgs(long[] msg_ids, ITLFunction query) + public Task InvokeAfterMsgs(long[] msg_ids, ITLFunction query) => CallAsync(writer => { writer.Write(0x3DC4B4F0); @@ -7027,7 +7027,7 @@ namespace WTelegram // ---functions--- }); ///See - public static ITLFunction InitConnection(int api_id, string device_model, string system_version, string app_version, string system_lang_code, string lang_pack, string lang_code, ITLFunction query, InputClientProxy proxy = null, JSONValue params_ = null) + public static ITLFunction InitConnection(int api_id, string device_model, string system_version, string app_version, string system_lang_code, string lang_pack, string lang_code, ITLFunction query, InputClientProxy proxy = null, JSONValue params_ = null) => writer => { writer.Write(0xC1CD5EA9); @@ -7044,7 +7044,7 @@ namespace WTelegram // ---functions--- if (params_ != null) writer.WriteTLObject(params_); query(writer); - return "InitConnection"; + return "InitConnection"; }; ///See @@ -7138,7 +7138,7 @@ namespace WTelegram // ---functions--- }); ///See - public Task InvokeWithLayer(int layer, ITLFunction query) + public Task InvokeWithLayer(int layer, ITLFunction query) => CallAsync(writer => { writer.Write(0xDA9B0D0D); @@ -7300,7 +7300,7 @@ namespace WTelegram // ---functions--- }); ///See - public Task InvokeWithoutUpdates(ITLFunction query) + public Task InvokeWithoutUpdates(ITLFunction query) => CallAsync(writer => { writer.Write(0xBF9459B7); @@ -8889,7 +8889,7 @@ namespace WTelegram // ---functions--- }); ///See - public Task InvokeWithMessagesRange(MessageRange range, ITLFunction query) + public Task InvokeWithMessagesRange(MessageRange range, ITLFunction query) => CallAsync(writer => { writer.Write(0x365275F2); @@ -8899,7 +8899,7 @@ namespace WTelegram // ---functions--- }); ///See - public Task InvokeWithTakeout(long takeout_id, ITLFunction query) + public Task InvokeWithTakeout(long takeout_id, ITLFunction query) => CallAsync(writer => { writer.Write(0xACA9FD2E); diff --git a/src/TL.cs b/src/TL.cs index 67b7738..3f66e75 100644 --- a/src/TL.cs +++ b/src/TL.cs @@ -11,7 +11,7 @@ using WTelegram; namespace TL { public interface ITLObject { } - public delegate string ITLFunction(BinaryWriter writer); + public delegate string ITLFunction(BinaryWriter writer); public static partial class Schema { @@ -51,14 +51,14 @@ namespace TL } } - internal static ITLObject ReadTLObject(this BinaryReader reader, Action notifyType = null) + internal static ITLObject ReadTLObject(this BinaryReader reader, Func customRead = null) { var ctorNb = reader.ReadUInt32(); if (ctorNb == NullCtor) return null; if (!Table.TryGetValue(ctorNb, out var type)) throw new ApplicationException($"Cannot find type for ctor #{ctorNb:x}"); var obj = Activator.CreateInstance(type); - notifyType?.Invoke(type, obj); + if (customRead?.Invoke(type) == true) return (ITLObject)obj; var fields = obj.GetType().GetFields().GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g); int flags = 0; IfFlagAttribute ifFlag;