diff --git a/Examples/Program_ListenUpdates.cs b/Examples/Program_ListenUpdates.cs index 37eb447..ff9e5d7 100644 --- a/Examples/Program_ListenUpdates.cs +++ b/Examples/Program_ListenUpdates.cs @@ -19,7 +19,7 @@ namespace WTelegramClientTest { Console.WriteLine("The program will display updates received for the logged-in user. Press any key to terminate"); WTelegram.Helpers.Log += (l, s) => System.Diagnostics.Debug.WriteLine(s); - using var client = new WTelegram.Client(Config);// { CollectAccessHash = true }; + using var client = new WTelegram.Client(Config) { CollectAccessHash = true }; client.Update += Client_Update; await client.ConnectAsync(); var my = await client.LoginUserIfNeeded(); @@ -28,20 +28,15 @@ namespace WTelegramClientTest Console.WriteLine($"We are logged-in as {my.username ?? my.first_name + " " + my.last_name} (id {my.id})"); var dialogsBase = await client.Messages_GetDialogs(default, 0, InputPeer.Empty, 0, 0); if (dialogsBase is Messages_Dialogs dialogs) - { - foreach (var user in dialogs.users) users[user.ID] = user; - foreach (var chat in dialogs.chats) chats[chat.ID] = chat; - } - else if (dialogsBase is Messages_DialogsSlice slice) - while (slice.dialogs.Length != 0) + while (dialogs.dialogs.Length != 0) { - foreach (var user in slice.users) users[user.ID] = user; - foreach (var chat in slice.chats) chats[chat.ID] = chat; - var lastDialog = (Dialog)slice.dialogs[^1]; - var lastMsg = slice.messages.LastOrDefault(m => m.Peer.ID == lastDialog.peer.ID && m.ID == lastDialog.top_message); - InputPeer offsetPeer = lastDialog.peer is PeerUser pu ? slice.users.First(u => u.ID == pu.ID) - : slice.chats.First(u => u.ID == lastDialog.peer.ID); - slice = (Messages_DialogsSlice)await client.Messages_GetDialogs(lastMsg?.Date ?? default, lastDialog.top_message, offsetPeer, 500, 0); + foreach (var user in dialogs.users) users[user.ID] = user; + foreach (var chat in dialogs.chats) chats[chat.ID] = chat; + var lastDialog = (Dialog)dialogs.dialogs[^1]; + var lastMsg = dialogs.messages.LastOrDefault(m => m.Peer.ID == lastDialog.peer.ID && m.ID == lastDialog.top_message); + InputPeer offsetPeer = lastDialog.peer is PeerUser pu ? dialogs.users.First(u => u.ID == pu.ID) + : dialogs.chats.First(u => u.ID == lastDialog.peer.ID); + dialogs = (Messages_Dialogs)await client.Messages_GetDialogs(lastMsg?.Date ?? default, lastDialog.top_message, offsetPeer, 500, 0); } Console.ReadKey(); await client.Ping(43); // dummy API call.. this is used to force an acknowledge on this session's updates @@ -83,10 +78,9 @@ namespace WTelegramClientTest { case UpdateNewMessage unm: DisplayMessage(unm.message); break; case UpdateEditMessage uem: Console.Write("(Edit): "); DisplayMessage(uem.message); break; - case UpdateDeleteMessages udm: Console.WriteLine($"{udm.messages.Length} message(s) deleted"); break; - case UpdateNewChannelMessage uncm: DisplayMessage(uncm.message); break; - case UpdateEditChannelMessage uecm: Console.Write("(Edit): "); DisplayMessage(uecm.message); break; case UpdateDeleteChannelMessages udcm: Console.WriteLine($"{udcm.messages.Length} message(s) deleted in {AChat(udcm.channel_id)}"); break; + case UpdateDeleteMessages udm: Console.WriteLine($"{udm.messages.Length} message(s) deleted"); break; + case UpdateEditChannelMessage uecm: Console.Write("(Edit): "); DisplayMessage(uecm.message); break; case UpdateUserTyping uut: Console.WriteLine($"{AUser(uut.user_id)} is {uut.action.GetType().Name[11..^6]}"); break; case UpdateChatUserTyping ucut: Console.WriteLine($"{APeer(ucut.from_id)} is {ucut.action.GetType().Name[11..^6]} in {AChat(ucut.chat_id)}"); break; case UpdateChannelUserTyping ucut2: Console.WriteLine($"{APeer(ucut2.from_id)} is {ucut2.action.GetType().Name[11..^6]} in {AChat(ucut2.channel_id)}"); break; diff --git a/README.md b/README.md index 11dc289..246c91d 100644 --- a/README.md +++ b/README.md @@ -73,10 +73,9 @@ Below is an example of calling the [messages.getAllChats](https://core.telegram. ```csharp using TL; ... -var chatsBase = await client.Messages_GetAllChats(null); -if (chatsBase is not Messages_Chats { chats: var chats }) throw new Exception("hu?"); +var chats = await client.Messages_GetAllChats(null); Console.WriteLine("This user has joined the following:"); -foreach (var chat in chats) +foreach (var chat in chats.chats) switch (chat) { case Chat smallgroup when (smallgroup.flags & Chat.Flags.deactivated) == 0: diff --git a/src/Generator.cs b/src/Generator.cs index a4ae70d..aa4aec3 100644 --- a/src/Generator.cs +++ b/src/Generator.cs @@ -14,9 +14,8 @@ namespace WTelegram { readonly Dictionary ctorToTypes = new(); readonly HashSet allTypes = new(); - readonly Dictionary> typeInfosByLayer = new(); readonly Dictionary knownStyles = new() { ["InitConnection"] = 1, ["Help_GetConfig"] = 0, ["HttpWait"] = -1 }; - Dictionary typeInfos; + readonly Dictionary typeInfos = new(); readonly HashSet enumTypes = new(); int currentLayer; string tabIndent; @@ -106,86 +105,96 @@ namespace WTelegram sw.WriteLine("\tusing BinaryWriter = System.IO.BinaryWriter;"); sw.WriteLine("\tusing Client = WTelegram.Client;"); tabIndent = "\t"; - var layers = schema.constructors.GroupBy(c => c.layer).OrderBy(g => g.Key); - foreach (var layer in layers) + foreach (var ctor in schema.constructors) { - typeInfos = typeInfosByLayer.GetOrCreate(layer.Key); - if (layer.Key != 0) + if (ctorToTypes.ContainsKey(ctor.ID)) continue; + if (ctor.type == "Vector t") continue; + var structName = CSharpName(ctor.predicate); + ctorToTypes[ctor.ID] = ctor.layer == 0 ? structName : $"Layer{ctor.layer}.{structName}"; + var typeInfo = typeInfos.GetOrCreate(ctor.type); + if (ctor.ID == 0x5BB8E511) { ctorToTypes[ctor.ID] = structName = ctor.predicate = ctor.type = "_Message"; } + if (typeInfo.ReturnName == null) typeInfo.ReturnName = CSharpName(ctor.type); + typeInfo.Structs.Add(ctor); + if (structName == typeInfo.ReturnName) typeInfo.MainClass = ctor; + } + foreach (var (name, typeInfo) in typeInfos) + { + if (allTypes.Contains(typeInfo.ReturnName)) { - sw.WriteLine(); - sw.WriteLine("\tnamespace Layer" + layer.Key); - sw.Write("\t{"); - tabIndent += "\t"; - } - string layerPrefix = layer.Key == 0 ? "" : $"Layer{layer.Key}."; - foreach (var ctor in layer) - { - if (ctorToTypes.ContainsKey(ctor.ID)) continue; - if (ctor.type == "Vector t") continue; - var structName = CSharpName(ctor.predicate); - ctorToTypes[ctor.ID] = layerPrefix + structName; - var typeInfo = typeInfos.GetOrCreate(ctor.type); - if (ctor.ID == 0x5BB8E511) { ctorToTypes[ctor.ID] = structName = ctor.predicate = ctor.type = "_Message"; } - if (typeInfo.ReturnName == null) typeInfo.ReturnName = CSharpName(ctor.type); - typeInfo.Structs.Add(ctor); - if (structName == typeInfo.ReturnName) typeInfo.MainClass = ctor; - } - foreach (var (name, typeInfo) in typeInfos) - { - if (allTypes.Contains(typeInfo.ReturnName)) + if (typeInfos.TryGetValue(typeInfo.ReturnName, out var existingType)) { - if (typeInfosByLayer[0].TryGetValue(typeInfo.ReturnName, out var existingType)) - { - typeInfo.ReturnName = existingType.ReturnName; - typeInfo.MainClass = existingType.MainClass; - } - continue; + typeInfo.ReturnName = existingType.ReturnName; + typeInfo.MainClass = existingType.MainClass; } - if (typeInfo.MainClass == null) + continue; + } + if (typeInfo.MainClass == null) + { + List fakeCtorParams = new(); + if (typeInfo.Structs.Count > 1) { - List fakeCtorParams = new(); - if (typeInfo.Structs.Count > 1) + while (typeInfo.Structs[0].@params.Length > fakeCtorParams.Count) { + fakeCtorParams.Add(typeInfo.Structs[0].@params[fakeCtorParams.Count]); + if (!typeInfo.Structs.All(ctor => HasPrefix(ctor, fakeCtorParams))) + { + fakeCtorParams.RemoveAt(fakeCtorParams.Count - 1); + break; + } + } + if (fakeCtorParams.Count == 0) while (typeInfo.Structs[0].@params.Length > fakeCtorParams.Count) { - fakeCtorParams.Add(typeInfo.Structs[0].@params[fakeCtorParams.Count]); - if (!typeInfo.Structs.All(ctor => HasPrefix(ctor, fakeCtorParams))) + fakeCtorParams.Insert(0, typeInfo.Structs[0].@params[^(fakeCtorParams.Count + 1)]); + if (!typeInfo.Structs.All(ctor => HasSuffix(ctor, fakeCtorParams))) { - fakeCtorParams.RemoveAt(fakeCtorParams.Count - 1); + fakeCtorParams.RemoveAt(0); break; } } - } - typeInfo.MainClass = new Constructor { id = null, @params = fakeCtorParams.ToArray(), predicate = typeInfo.ReturnName, type = name }; - typeInfo.Structs.Insert(0, typeInfo.MainClass); - typeInfo.CommonFields = fakeCtorParams.Count; // generation of abstract main class with some common fields } - else if (typeInfo.Structs.Count > 1) + typeInfo.MainClass = new Constructor { id = null, @params = fakeCtorParams.ToArray(), predicate = typeInfo.ReturnName, type = name }; + typeInfo.Structs.Insert(0, typeInfo.MainClass); + typeInfo.CommonFields = fakeCtorParams.Count; // generation of abstract main class with some common fields + } + else if (typeInfo.Structs.Count > 1) + { + if (typeInfo.Structs.All(ctor => ctor == typeInfo.MainClass || HasPrefix(ctor, typeInfo.MainClass.@params) || HasSuffix(ctor, typeInfo.MainClass.@params))) + typeInfo.CommonFields = typeInfo.MainClass.@params.Length; + else { - if (typeInfo.Structs.All(ctor => ctor == typeInfo.MainClass || HasPrefix(ctor, typeInfo.MainClass.@params))) - typeInfo.CommonFields = typeInfo.MainClass.@params.Length; - else - { - // the previous MainClass (ctor have the same name as ReturnName) is incompatible with other classes fields - typeInfo.MainClass = new Constructor { id = null, @params = Array.Empty(), predicate = typeInfo.ReturnName + "Base", type = name }; - typeInfo.Structs.Insert(0, typeInfo.MainClass); - typeInfo.ReturnName = typeInfo.MainClass.predicate; - } + // the previous MainClass (ctor have the same name as ReturnName) is incompatible with other classes fields + typeInfo.MainClass = new Constructor { id = null, @params = Array.Empty(), predicate = typeInfo.ReturnName + "Base", type = name }; + typeInfo.Structs.Insert(0, typeInfo.MainClass); + typeInfo.ReturnName = typeInfo.MainClass.predicate; } } + } + var layers = schema.constructors.Select(c => c.layer).Distinct().ToList(); + if (layers.Count > 1) // multi-layer file => generate abstract classes out of layer namespaces first foreach (var typeInfo in typeInfos.Values) - WriteTypeInfo(sw, typeInfo, layerPrefix, false); - if (layer.Key != 0) + WriteTypeInfo(sw, typeInfo, 0); + foreach (var layer in layers) + { + if (layer != 0) + { + sw.WriteLine(); + sw.WriteLine("\tnamespace Layer" + layer); + sw.Write("\t{"); + tabIndent += "\t"; + } + foreach (var typeInfo in typeInfos.Values) + WriteTypeInfo(sw, typeInfo, layer); + if (layer != 0) { sw.WriteLine("\t}"); tabIndent = tabIndent[1..]; } } - if (typeInfosByLayer[0].GetValueOrDefault("Message")?.MainClass.ID == 0x5BB8E511) typeInfosByLayer[0].Remove("Message"); + if (typeInfos.GetValueOrDefault("Message")?.MainClass.ID == 0x5BB8E511) typeInfos.Remove("Message"); if (schema.methods.Count != 0) { - typeInfos = typeInfosByLayer[0]; var ping = schema.methods.FirstOrDefault(m => m.method == "ping"); if (ping != null) { @@ -193,7 +202,7 @@ namespace WTelegram new Constructor { id = ping.id, @params = ping.@params, predicate = ping.method, type = ping.type } }; typeInfo.Structs.Add(typeInfo.MainClass); ctorToTypes[int.Parse(ping.id)] = CSharpName(ping.method); - WriteTypeInfo(sw, typeInfo, "", false); + WriteTypeInfo(sw, typeInfo, 0); } sw.WriteLine(); sw.WriteLine("\t// ---functions---"); @@ -217,17 +226,21 @@ namespace WTelegram UpdateTable("TL.Table.cs"); } - void WriteTypeInfo(StreamWriter sw, TypeInfo typeInfo, string layerPrefix, bool isMethod) + void WriteTypeInfo(StreamWriter sw, TypeInfo typeInfo, int layer) { var genericType = typeInfo.ReturnName.Length == 1 ? $"<{typeInfo.ReturnName}>" : null; bool needNewLine = true; - int skipParams = 0; - foreach (var ctor in typeInfo.Structs) + int commonFields = 0; + for (int i = 0; i < typeInfo.Structs.Count; i++) { + var ctor = typeInfo.Structs[i]; + if (ctor.layer != layer) continue; int ctorId = ctor.ID; string className = CSharpName(ctor.predicate) + genericType; - if (!allTypes.Add(layerPrefix + className)) continue; + if (!allTypes.Add((layer == 0 ? "" : $"Layer{layer}.") + className)) continue; if (needNewLine) { needNewLine = false; sw.WriteLine(); } + var parentClass = ctor == typeInfo.MainClass ? "ITLObject" : typeInfo.ReturnName; + var parms = ctor.@params; if (ctorId == 0) { if (currentJson != "TL.MTProto") @@ -241,14 +254,49 @@ namespace WTelegram } else { - if (currentJson != "TL.MTProto") + string tldefReverse = null; + if (commonFields != 0) { - sw.WriteLine($"{tabIndent}///See "); - sw.WriteLine($"{tabIndent}[TLDef(0x{ctor.ID:X8})]"); + if (ctor.@params[0].name == typeInfo.MainClass.@params[0].name) + parms = ctor.@params.Skip(commonFields).ToArray(); + else + { + parms = ctor.@params.Take(ctor.@params.Length - commonFields).ToArray(); + tldefReverse = ", inheritAfter = true"; + } } else { - sw.Write($"{tabIndent}[TLDef(0x{ctor.ID:X8})] //{ctor.predicate}#{ctor.ID:x8} "); + for (int j = i - 1; j >= 0; j--) + { + var otherParams = typeInfo.Structs[j].@params; + if (otherParams.Length <= commonFields) continue; + var otherPredicate = typeInfo.Structs[j].predicate; + if (!IsDerivedName(ctor.predicate, otherPredicate)) continue; + if (HasPrefix(ctor, otherParams)) + { + parms = ctor.@params.Skip(otherParams.Length).ToArray(); + tldefReverse = null; + } + else if (HasSuffix(ctor, otherParams)) + { + parms = ctor.@params.Take(ctor.@params.Length - otherParams.Length).ToArray(); + tldefReverse = ", inheritAfter = true"; + } + + else continue; + commonFields = otherParams.Length; + parentClass = CSharpName(otherPredicate) + genericType; + } + } + if (currentJson != "TL.MTProto") + { + sw.WriteLine($"{tabIndent}///See "); + sw.WriteLine($"{tabIndent}[TLDef(0x{ctor.ID:X8}{tldefReverse})]"); + } + else + { + sw.Write($"{tabIndent}[TLDef(0x{ctor.ID:X8}{tldefReverse})] //{ctor.predicate}#{ctor.ID:x8} "); if (genericType != null) sw.Write($"{{{typeInfo.ReturnName}:Type}} "); foreach (var parm in ctor.@params) sw.Write($"{parm.name}:{parm.type} "); sw.WriteLine($"= {ctor.type}"); @@ -257,11 +305,11 @@ namespace WTelegram //sw.Write(skipParams == 0 && typeInfo.NeedAbstract > 0 ? "ITLObject" : parentClass); } sw.Write(" : "); - sw.Write(ctor == typeInfo.MainClass ? "ITLObject" : typeInfo.ReturnName); - var parms = ctor.@params.Skip(skipParams).ToArray(); + sw.Write(parentClass); if (parms.Length == 0) { sw.WriteLine(" { }"); + commonFields = typeInfo.CommonFields; continue; } var hasFlagEnum = parms.Any(p => p.type.StartsWith("flags.")); @@ -323,10 +371,24 @@ namespace WTelegram sw.WriteLine(tabIndent + "}"); else sw.WriteLine(" }"); - skipParams = typeInfo.CommonFields; + commonFields = typeInfo.CommonFields; } } + private static bool IsDerivedName(string derived, string basename) + { + int left, right; + if (basename.Length >= derived.Length) return false; + for (left = 0; left < basename.Length; left++) + if (basename[left] != derived[left]) + break; + if (left == 0) return false; + for (right = 1; left + right <= basename.Length; right++) + if (basename[^right] != derived[^right]) + break; + return left + right > basename.Length; + } + private void WriteTypeAsEnum(StreamWriter sw, TypeInfo typeInfo) { enumTypes.Add(typeInfo.ReturnName); @@ -397,9 +459,9 @@ namespace WTelegram return typeInfo.ReturnName; else { // try to find type in a lower layer - foreach (var layer in typeInfosByLayer.OrderByDescending(kvp => kvp.Key)) + /*foreach (var layer in typeInfosByLayer.OrderByDescending(kvp => kvp.Key)) if (layer.Value.TryGetValue(type, out typeInfo)) - return layer.Key == 0 ? typeInfo.ReturnName : $"Layer{layer.Key}.{typeInfo.ReturnName}"; + return layer.Key == 0 ? typeInfo.ReturnName : $"Layer{layer.Key}.{typeInfo.ReturnName}";*/ return CSharpName(type); } } @@ -588,6 +650,15 @@ namespace WTelegram return true; } + private static bool HasSuffix(Constructor ctor, IList prefixParams) + { + if (ctor.@params.Length < prefixParams.Count) return false; + for (int i = 1; i <= prefixParams.Count; i++) + if (ctor.@params[^i].name != prefixParams[^i].name || ctor.@params[^i].type != prefixParams[^i].type) + return false; + return true; + } + private static string CSharpName(string name) { name = char.ToUpper(name[0]) + name[1..]; diff --git a/src/TL.Schema.cs b/src/TL.Schema.cs index 80dd9d0..18d5e73 100644 --- a/src/TL.Schema.cs +++ b/src/TL.Schema.cs @@ -648,12 +648,7 @@ namespace TL public partial class ChatParticipantCreator : ChatParticipantBase { public long user_id; } ///See [TLDef(0xA0933F5B)] - public partial class ChatParticipantAdmin : ChatParticipantBase - { - public long user_id; - public long inviter_id; - public DateTime date; - } + public partial class ChatParticipantAdmin : ChatParticipant { } ///See public abstract partial class ChatParticipantsBase : ITLObject { } @@ -1312,25 +1307,17 @@ namespace TL public UserBase[] users; } - ///See - public abstract partial class Contacts_BlockedBase : ITLObject { } ///See [TLDef(0x0ADE1591)] - public partial class Contacts_Blocked : Contacts_BlockedBase + public partial class Contacts_Blocked : ITLObject { public PeerBlocked[] blocked; public ChatBase[] chats; public UserBase[] users; } ///See - [TLDef(0xE1664194)] - public partial class Contacts_BlockedSlice : Contacts_BlockedBase - { - public int count; - public PeerBlocked[] blocked; - public ChatBase[] chats; - public UserBase[] users; - } + [TLDef(0xE1664194, inheritAfter = true)] + public partial class Contacts_BlockedSlice : Contacts_Blocked { public int count; } ///See public abstract partial class Messages_DialogsBase : ITLObject { } @@ -1344,15 +1331,8 @@ namespace TL public UserBase[] users; } ///See - [TLDef(0x71E094F3)] - public partial class Messages_DialogsSlice : Messages_DialogsBase - { - public int count; - public DialogBase[] dialogs; - public MessageBase[] messages; - public ChatBase[] chats; - public UserBase[] users; - } + [TLDef(0x71E094F3, inheritAfter = true)] + public partial class Messages_DialogsSlice : Messages_Dialogs { public int count; } ///See [TLDef(0xF0E3E596)] public partial class Messages_DialogsNotModified : Messages_DialogsBase { public int count; } @@ -1368,17 +1348,14 @@ namespace TL public UserBase[] users; } ///See - [TLDef(0x3A54685E)] - public partial class Messages_MessagesSlice : Messages_MessagesBase + [TLDef(0x3A54685E, inheritAfter = true)] + public partial class Messages_MessagesSlice : Messages_Messages { [Flags] public enum Flags { has_next_rate = 0x1, inexact = 0x2, has_offset_id_offset = 0x4 } public Flags flags; public int count; [IfFlag(0)] public int next_rate; [IfFlag(2)] public int offset_id_offset; - public MessageBase[] messages; - public ChatBase[] chats; - public UserBase[] users; } ///See [TLDef(0x64479808)] @@ -1397,18 +1374,12 @@ namespace TL [TLDef(0x74535F21)] public partial class Messages_MessagesNotModified : Messages_MessagesBase { public int count; } - ///See - public abstract partial class Messages_ChatsBase : ITLObject { } ///See [TLDef(0x64FF9FD5)] - public partial class Messages_Chats : Messages_ChatsBase { public ChatBase[] chats; } + public partial class Messages_Chats : ITLObject { public ChatBase[] chats; } ///See - [TLDef(0x9CD81144)] - public partial class Messages_ChatsSlice : Messages_ChatsBase - { - public int count; - public ChatBase[] chats; - } + [TLDef(0x9CD81144, inheritAfter = true)] + public partial class Messages_ChatsSlice : Messages_Chats { public int count; } ///See [TLDef(0xE5D7D19C)] @@ -1685,12 +1656,7 @@ namespace TL public partial class UpdateChannel : Update { public long channel_id; } ///See [TLDef(0x62BA04D9)] - public partial class UpdateNewChannelMessage : Update - { - public MessageBase message; - public int pts; - public int pts_count; - } + public partial class UpdateNewChannelMessage : UpdateNewMessage { } ///See [TLDef(0x922E6E10)] public partial class UpdateReadChannelInbox : Update @@ -1704,19 +1670,12 @@ namespace TL public int pts; } ///See - [TLDef(0xC32D5B12)] - public partial class UpdateDeleteChannelMessages : Update - { - public long channel_id; - public int[] messages; - public int pts; - public int pts_count; - } + [TLDef(0xC32D5B12, inheritAfter = true)] + public partial class UpdateDeleteChannelMessages : UpdateDeleteMessages { public long channel_id; } ///See [TLDef(0xF226AC08)] - public partial class UpdateChannelMessageViews : Update + public partial class UpdateChannelMessageViews : UpdateChannel { - public long channel_id; public int id; public int views; } @@ -1841,14 +1800,8 @@ namespace TL [TLDef(0x3354678F)] public partial class UpdatePtsChanged : Update { } ///See - [TLDef(0x2F2BA99F)] - public partial class UpdateChannelWebPage : Update - { - public long channel_id; - public WebPageBase webpage; - public int pts; - public int pts_count; - } + [TLDef(0x2F2BA99F, inheritAfter = true)] + public partial class UpdateChannelWebPage : UpdateWebPage { public long channel_id; } ///See [TLDef(0x6E6FE51C)] public partial class UpdateDialogPinned : Update @@ -1915,21 +1868,13 @@ namespace TL public partial class UpdateFavedStickers : Update { } ///See [TLDef(0x44BDD535)] - public partial class UpdateChannelReadMessagesContents : Update - { - public long channel_id; - public int[] messages; - } + public partial class UpdateChannelReadMessagesContents : UpdateChannel { public int[] messages; } ///See [TLDef(0x7084A7BE)] public partial class UpdateContactsReset : Update { } ///See [TLDef(0xB23FC698)] - public partial class UpdateChannelAvailableMessages : Update - { - public long channel_id; - public int available_min_id; - } + public partial class UpdateChannelAvailableMessages : UpdateChannel { public int available_min_id; } ///See [TLDef(0xE16459C3)] public partial class UpdateDialogUnreadMark : Update @@ -2030,9 +1975,8 @@ namespace TL } ///See [TLDef(0xD29A27F4)] - public partial class UpdateChannelMessageForwards : Update + public partial class UpdateChannelMessageForwards : UpdateChannel { - public long channel_id; public int id; public int forwards; } @@ -2312,23 +2256,16 @@ namespace TL [IfFlag(25)] public int ttl_period; } - ///See - public abstract partial class Photos_PhotosBase : ITLObject { } ///See [TLDef(0x8DCA6AA5)] - public partial class Photos_Photos : Photos_PhotosBase + public partial class Photos_Photos : ITLObject { public PhotoBase[] photos; public UserBase[] users; } ///See - [TLDef(0x15051F54)] - public partial class Photos_PhotosSlice : Photos_PhotosBase - { - public int count; - public PhotoBase[] photos; - public UserBase[] users; - } + [TLDef(0x15051F54, inheritAfter = true)] + public partial class Photos_PhotosSlice : Photos_Photos { public int count; } ///See [TLDef(0x20212CA8)] @@ -3180,11 +3117,7 @@ namespace TL public partial class KeyboardButton : KeyboardButtonBase { public string text; } ///See [TLDef(0x258AFF05)] - public partial class KeyboardButtonUrl : KeyboardButtonBase - { - public string text; - public string url; - } + public partial class KeyboardButtonUrl : KeyboardButton { public string url; } ///See [TLDef(0x35BBDB6B)] public partial class KeyboardButtonCallback : KeyboardButtonBase @@ -3196,10 +3129,10 @@ namespace TL } ///See [TLDef(0xB16A6C29)] - public partial class KeyboardButtonRequestPhone : KeyboardButtonBase { public string text; } + public partial class KeyboardButtonRequestPhone : KeyboardButton { } ///See [TLDef(0xFC796B3F)] - public partial class KeyboardButtonRequestGeoLocation : KeyboardButtonBase { public string text; } + public partial class KeyboardButtonRequestGeoLocation : KeyboardButton { } ///See [TLDef(0x0568A748)] public partial class KeyboardButtonSwitchInline : KeyboardButtonBase @@ -3211,10 +3144,10 @@ namespace TL } ///See [TLDef(0x50F41CCF)] - public partial class KeyboardButtonGame : KeyboardButtonBase { public string text; } + public partial class KeyboardButtonGame : KeyboardButton { } ///See [TLDef(0xAFD93FBB)] - public partial class KeyboardButtonBuy : KeyboardButtonBase { public string text; } + public partial class KeyboardButtonBuy : KeyboardButton { } ///See [TLDef(0x10B78D29)] public partial class KeyboardButtonUrlAuth : KeyboardButtonBase @@ -3238,13 +3171,12 @@ namespace TL public InputUserBase bot; } ///See - [TLDef(0xBBC7515D)] - public partial class KeyboardButtonRequestPoll : KeyboardButtonBase + [TLDef(0xBBC7515D, inheritAfter = true)] + public partial class KeyboardButtonRequestPoll : KeyboardButton { [Flags] public enum Flags { has_quiz = 0x1 } public Flags flags; [IfFlag(0)] public bool quiz; - public string text; } ///See @@ -5393,20 +5325,10 @@ namespace TL } ///See [TLDef(0xA1144770)] - public partial class SecureValueErrorTranslationFile : SecureValueErrorBase - { - public SecureValueType type; - public byte[] file_hash; - public string text; - } + public partial class SecureValueErrorTranslationFile : SecureValueErrorFile { } ///See [TLDef(0x34636DD8)] - public partial class SecureValueErrorTranslationFiles : SecureValueErrorBase - { - public SecureValueType type; - public byte[][] file_hash; - public string text; - } + public partial class SecureValueErrorTranslationFiles : SecureValueErrorFiles { } ///See [TLDef(0x33F0EA47)] @@ -6666,14 +6588,10 @@ namespace TL public partial class BotCommandScopePeer : BotCommandScope { public InputPeer peer; } ///See [TLDef(0x3FD863D1)] - public partial class BotCommandScopePeerAdmins : BotCommandScope { public InputPeer peer; } + public partial class BotCommandScopePeerAdmins : BotCommandScopePeer { } ///See [TLDef(0x0A1321F3)] - public partial class BotCommandScopePeerUser : BotCommandScope - { - public InputPeer peer; - public InputUserBase user_id; - } + public partial class BotCommandScopePeerUser : BotCommandScopePeer { public InputUserBase user_id; } ///See public abstract partial class Account_ResetPasswordResult : ITLObject { } @@ -7805,8 +7723,8 @@ namespace TL }); ///See - public static Task Contacts_GetBlocked(this Client client, int offset, int limit) - => client.CallAsync(writer => + public static Task Contacts_GetBlocked(this Client client, int offset, int limit) + => client.CallAsync(writer => { writer.Write(0xF57C350F); writer.Write(offset); @@ -8129,8 +8047,8 @@ namespace TL }); ///See - public static Task Messages_GetChats(this Client client, long[] id) - => client.CallAsync(writer => + public static Task Messages_GetChats(this Client client, long[] id) + => client.CallAsync(writer => { writer.Write(0x49E9528F); writer.WriteTLVector(id); @@ -8799,8 +8717,8 @@ namespace TL }); ///See - public static Task Messages_GetCommonChats(this Client client, InputUserBase user_id, long max_id, int limit) - => client.CallAsync(writer => + public static Task Messages_GetCommonChats(this Client client, InputUserBase user_id, long max_id, int limit) + => client.CallAsync(writer => { writer.Write(0xE40CA104); writer.WriteTLObject(user_id); @@ -8810,8 +8728,8 @@ namespace TL }); ///See - public static Task Messages_GetAllChats(this Client client, long[] except_ids) - => client.CallAsync(writer => + public static Task Messages_GetAllChats(this Client client, long[] except_ids) + => client.CallAsync(writer => { writer.Write(0x875F74BE); writer.WriteTLVector(except_ids); @@ -9602,8 +9520,8 @@ namespace TL }); ///See - public static Task Photos_GetUserPhotos(this Client client, InputUserBase user_id, int offset, long max_id, int limit) - => client.CallAsync(writer => + public static Task Photos_GetUserPhotos(this Client client, InputUserBase user_id, int offset, long max_id, int limit) + => client.CallAsync(writer => { writer.Write(0x91CD32A8); writer.WriteTLObject(user_id); @@ -9969,8 +9887,8 @@ namespace TL }); ///See - public static Task Channels_GetChannels(this Client client, InputChannelBase[] id) - => client.CallAsync(writer => + public static Task Channels_GetChannels(this Client client, InputChannelBase[] id) + => client.CallAsync(writer => { writer.Write(0x0A7F6BBB); writer.WriteTLVector(id); @@ -10112,8 +10030,8 @@ namespace TL }); ///See - public static Task Channels_GetAdminedPublicChannels(this Client client, bool by_location = false, bool check_limit = false) - => client.CallAsync(writer => + public static Task Channels_GetAdminedPublicChannels(this Client client, bool by_location = false, bool check_limit = false) + => client.CallAsync(writer => { writer.Write(0xF8B036AF); writer.Write((by_location ? 0x1 : 0) | (check_limit ? 0x2 : 0)); @@ -10190,8 +10108,8 @@ namespace TL }); ///See - public static Task Channels_GetLeftChannels(this Client client, int offset) - => client.CallAsync(writer => + public static Task Channels_GetLeftChannels(this Client client, int offset) + => client.CallAsync(writer => { writer.Write(0x8341ECC0); writer.Write(offset); @@ -10199,8 +10117,8 @@ namespace TL }); ///See - public static Task Channels_GetGroupsForDiscussion(this Client client) - => client.CallAsync(writer => + public static Task Channels_GetGroupsForDiscussion(this Client client) + => client.CallAsync(writer => { writer.Write(0xF5DAD378); return "Channels_GetGroupsForDiscussion"; diff --git a/src/TL.Secret.cs b/src/TL.Secret.cs index 382af68..3d7e81b 100644 --- a/src/TL.Secret.cs +++ b/src/TL.Secret.cs @@ -6,10 +6,20 @@ namespace TL using BinaryWriter = System.IO.BinaryWriter; using Client = WTelegram.Client; + ///See + public abstract partial class DecryptedMessageBase : ITLObject { } + + ///See + public abstract partial class DecryptedMessageMedia : ITLObject { } + + ///See + public abstract partial class DecryptedMessageAction : ITLObject { } + + ///See + public abstract partial class FileLocationBase : ITLObject { } + namespace Layer8 { - ///See - public abstract partial class DecryptedMessageBase : ITLObject { } ///See [TLDef(0x1F814F1F)] public partial class DecryptedMessage : DecryptedMessageBase @@ -28,8 +38,6 @@ namespace TL public DecryptedMessageAction action; } - ///See - public abstract partial class DecryptedMessageMedia : ITLObject { } ///See [TLDef(0x089F5C4A)] public partial class DecryptedMessageMediaEmpty : DecryptedMessageMedia { } @@ -99,8 +107,6 @@ namespace TL public byte[] iv; } - ///See - public abstract partial class DecryptedMessageAction : ITLObject { } ///See [TLDef(0xA1733AEC)] public partial class DecryptedMessageActionSetMessageTTL : DecryptedMessageAction { public int ttl_seconds; } @@ -120,8 +126,19 @@ namespace TL namespace Layer17 { - ///See - public abstract partial class DecryptedMessageBase : ITLObject { } + ///See + [TLDef(0x92042FF7)] + public partial class SendMessageUploadVideoAction : SendMessageAction { } + ///See + [TLDef(0xE6AC8A6F)] + public partial class SendMessageUploadAudioAction : SendMessageAction { } + ///See + [TLDef(0x990A3C1A)] + public partial class SendMessageUploadPhotoAction : SendMessageAction { } + ///See + [TLDef(0x8FAEE98E)] + public partial class SendMessageUploadDocumentAction : SendMessageAction { } + ///See [TLDef(0x204D3878)] public partial class DecryptedMessage : DecryptedMessageBase @@ -139,8 +156,6 @@ namespace TL public DecryptedMessageAction action; } - ///See - public abstract partial class DecryptedMessageMedia : ITLObject { } ///See [TLDef(0x524A415D)] public partial class DecryptedMessageMediaVideo : DecryptedMessageMedia @@ -167,32 +182,6 @@ namespace TL public byte[] iv; } - ///See - [TLDef(0x1BE31789)] - public partial class DecryptedMessageLayer : ITLObject - { - public byte[] random_bytes; - public int layer; - public int in_seq_no; - public int out_seq_no; - public DecryptedMessageBase message; - } - - ///See - [TLDef(0x92042FF7)] - public partial class SendMessageUploadVideoAction : SendMessageAction { } - ///See - [TLDef(0xE6AC8A6F)] - public partial class SendMessageUploadAudioAction : SendMessageAction { } - ///See - [TLDef(0x990A3C1A)] - public partial class SendMessageUploadPhotoAction : SendMessageAction { } - ///See - [TLDef(0x8FAEE98E)] - public partial class SendMessageUploadDocumentAction : SendMessageAction { } - - ///See - public abstract partial class DecryptedMessageAction : ITLObject { } ///See [TLDef(0x511110B0)] public partial class DecryptedMessageActionResend : DecryptedMessageAction @@ -206,122 +195,40 @@ namespace TL ///See [TLDef(0xCCB27641)] public partial class DecryptedMessageActionTyping : DecryptedMessageAction { public SendMessageAction action; } - } - namespace Layer20 - { - ///See - public abstract partial class DecryptedMessageAction : ITLObject { } - ///See - [TLDef(0xF3C9611B)] - public partial class DecryptedMessageActionRequestKey : DecryptedMessageAction + ///See + [TLDef(0x1BE31789)] + public partial class DecryptedMessageLayer : ITLObject { - public long exchange_id; - public byte[] g_a; - } - ///See - [TLDef(0x6FE1735B)] - public partial class DecryptedMessageActionAcceptKey : DecryptedMessageAction - { - public long exchange_id; - public byte[] g_b; - public long key_fingerprint; - } - ///See - [TLDef(0xDD05EC6B)] - public partial class DecryptedMessageActionAbortKey : DecryptedMessageAction { public long exchange_id; } - ///See - [TLDef(0xEC2E0B9B)] - public partial class DecryptedMessageActionCommitKey : DecryptedMessageAction - { - public long exchange_id; - public long key_fingerprint; - } - ///See - [TLDef(0xA82FDD63)] - public partial class DecryptedMessageActionNoop : DecryptedMessageAction { } - } - - namespace Layer23 - { - ///See - [TLDef(0xFB0A5727)] - public partial class DocumentAttributeSticker : DocumentAttribute { } - ///See - [TLDef(0x5910CCCB)] - public partial class DocumentAttributeVideo : DocumentAttribute - { - public int duration; - public int w; - public int h; - } - ///See - [TLDef(0x051448E5)] - public partial class DocumentAttributeAudio : DocumentAttribute { public int duration; } - - ///See - [TLDef(0x77BFB61B)] - public partial class PhotoSize : PhotoSizeBase - { - public string type; - public FileLocationBase location; - public int w; - public int h; - public int size; - } - ///See - [TLDef(0xE9A734FA)] - public partial class PhotoCachedSize : PhotoSizeBase - { - public string type; - public FileLocationBase location; - public int w; - public int h; - public byte[] bytes; - } - - ///See - public abstract partial class FileLocationBase : ITLObject { } - ///See - [TLDef(0x7C596B46)] - public partial class FileLocationUnavailable : FileLocationBase - { - public long volume_id; - public int local_id; - public long secret; - } - ///See - [TLDef(0x53D69076)] - public partial class FileLocation : FileLocationBase - { - public int dc_id; - public long volume_id; - public int local_id; - public long secret; - } - - ///See - public abstract partial class DecryptedMessageMedia : ITLObject { } - ///See - [TLDef(0xFA95B0DD)] - public partial class DecryptedMessageMediaExternalDocument : DecryptedMessageMedia - { - public long id; - public long access_hash; - public DateTime date; - public string mime_type; - public int size; - public PhotoSizeBase thumb; - public int dc_id; - public DocumentAttribute[] attributes; + public byte[] random_bytes; + public int layer; + public int in_seq_no; + public int out_seq_no; + public DecryptedMessageBase message; } } namespace Layer45 { + ///See + [TLDef(0x3A556302)] + public partial class DocumentAttributeSticker : DocumentAttribute + { + public string alt; + public InputStickerSet stickerset; + } + ///See + [TLDef(0xDED218E0)] + public partial class DocumentAttributeAudio : DocumentAttribute + { + public int duration; + public string title; + public string performer; + } + ///See [TLDef(0x36B091DE)] - public partial class DecryptedMessage : ITLObject + public partial class DecryptedMessage : DecryptedMessageBase { [Flags] public enum Flags { has_reply_to_random_id = 0x8, has_entities = 0x80, has_media = 0x200, has_via_bot_name = 0x800 } public Flags flags; @@ -334,8 +241,6 @@ namespace TL [IfFlag(3)] public long reply_to_random_id; } - ///See - public abstract partial class DecryptedMessageMedia : ITLObject { } ///See [TLDef(0xF1FA8D78)] public partial class DecryptedMessageMediaPhoto : DecryptedMessageMedia @@ -394,26 +299,130 @@ namespace TL ///See [TLDef(0xE50511D8)] public partial class DecryptedMessageMediaWebPage : DecryptedMessageMedia { public string url; } + } - ///See - [TLDef(0x3A556302)] - public partial class DocumentAttributeSticker : DocumentAttribute + namespace Layer73 + { + ///See + [TLDef(0x91CC4674)] + public partial class DecryptedMessage : DecryptedMessageBase { - public string alt; - public InputStickerSet stickerset; - } - ///See - [TLDef(0xDED218E0)] - public partial class DocumentAttributeAudio : DocumentAttribute - { - public int duration; - public string title; - public string performer; + [Flags] public enum Flags { has_reply_to_random_id = 0x8, has_entities = 0x80, has_media = 0x200, has_via_bot_name = 0x800, + has_grouped_id = 0x20000 } + public Flags flags; + public long random_id; + public int ttl; + public string message; + [IfFlag(9)] public DecryptedMessageMedia media; + [IfFlag(7)] public MessageEntity[] entities; + [IfFlag(11)] public string via_bot_name; + [IfFlag(3)] public long reply_to_random_id; + [IfFlag(17)] public long grouped_id; } } - namespace Layer46 - { } + namespace Layer20 + { + ///See + [TLDef(0xF3C9611B)] + public partial class DecryptedMessageActionRequestKey : DecryptedMessageAction + { + public long exchange_id; + public byte[] g_a; + } + ///See + [TLDef(0x6FE1735B)] + public partial class DecryptedMessageActionAcceptKey : DecryptedMessageAction + { + public long exchange_id; + public byte[] g_b; + public long key_fingerprint; + } + ///See + [TLDef(0xDD05EC6B)] + public partial class DecryptedMessageActionAbortKey : DecryptedMessageAction { public long exchange_id; } + ///See + [TLDef(0xEC2E0B9B)] + public partial class DecryptedMessageActionCommitKey : DecryptedMessageAction + { + public long exchange_id; + public long key_fingerprint; + } + ///See + [TLDef(0xA82FDD63)] + public partial class DecryptedMessageActionNoop : DecryptedMessageAction { } + } + + namespace Layer23 + { + ///See + [TLDef(0x77BFB61B)] + public partial class PhotoSize : PhotoSizeBase + { + public string type; + public FileLocationBase location; + public int w; + public int h; + public int size; + } + ///See + [TLDef(0xE9A734FA)] + public partial class PhotoCachedSize : PhotoSizeBase + { + public string type; + public FileLocationBase location; + public int w; + public int h; + public byte[] bytes; + } + + ///See + [TLDef(0xFB0A5727)] + public partial class DocumentAttributeSticker : DocumentAttribute { } + ///See + [TLDef(0x5910CCCB)] + public partial class DocumentAttributeVideo : DocumentAttribute + { + public int duration; + public int w; + public int h; + } + ///See + [TLDef(0x051448E5)] + public partial class DocumentAttributeAudio : DocumentAttribute { public int duration; } + + ///See + [TLDef(0xFA95B0DD)] + public partial class DecryptedMessageMediaExternalDocument : DecryptedMessageMedia + { + public long id; + public long access_hash; + public DateTime date; + public string mime_type; + public int size; + public PhotoSizeBase thumb; + public int dc_id; + public DocumentAttribute[] attributes; + } + + ///See + [TLDef(0x7C596B46)] + public partial class FileLocationUnavailable : FileLocationBase + { + public long volume_id; + public int local_id; + public long secret; + } + ///See + [TLDef(0x53D69076)] + public partial class FileLocation : FileLocationBase + { + public int dc_id; + public long volume_id; + public int local_id; + public long secret; + } + } namespace Layer66 { @@ -422,23 +431,6 @@ namespace TL public partial class SendMessageUploadRoundAction : SendMessageAction { } } - namespace Layer73 - { - ///See - [TLDef(0x91CC4674)] - public partial class DecryptedMessage : ITLObject - { - [Flags] public enum Flags { has_reply_to_random_id = 0x8, has_entities = 0x80, has_media = 0x200, has_via_bot_name = 0x800, - has_grouped_id = 0x20000 } - public Flags flags; - public long random_id; - public int ttl; - public string message; - [IfFlag(9)] public Layer45.DecryptedMessageMedia media; - [IfFlag(7)] public MessageEntity[] entities; - [IfFlag(11)] public string via_bot_name; - [IfFlag(3)] public long reply_to_random_id; - [IfFlag(17)] public long grouped_id; - } - } + namespace Layer46 + { } } diff --git a/src/TL.cs b/src/TL.cs index f2829b0..f199ce9 100644 --- a/src/TL.cs +++ b/src/TL.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; @@ -32,9 +33,11 @@ namespace TL { if (obj == null) { writer.Write(Layer.NullCtor); return; } var type = obj.GetType(); - var ctorNb = type.GetCustomAttribute().CtorNb; + var tlDef = type.GetCustomAttribute(); + var ctorNb = tlDef.CtorNb; writer.Write(ctorNb); - var fields = obj.GetType().GetFields().GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g); + IEnumerable fields = type.GetFields(); + if (!tlDef.inheritAfter) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g); int flags = 0; IfFlagAttribute ifFlag; foreach (var field in fields) @@ -55,8 +58,10 @@ namespace TL if (ctorNb == Layer.NullCtor) return null; if (!Layer.Table.TryGetValue(ctorNb, out var type)) throw new ApplicationException($"Cannot find type for ctor #{ctorNb:x}"); + var tlDef = type.GetCustomAttribute(); var obj = Activator.CreateInstance(type); - var fields = type.GetFields().GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g); + IEnumerable fields = type.GetFields(); + if (!tlDef.inheritAfter) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g); int flags = 0; IfFlagAttribute ifFlag; foreach (var field in fields) @@ -258,6 +263,7 @@ namespace TL { public readonly uint CtorNb; public TLDefAttribute(uint ctorNb) => CtorNb = ctorNb; + public bool inheritAfter; } [AttributeUsage(AttributeTargets.Field)]