diff --git a/generator/src/main/java/io/github/lonamiwebs/overgram/generator/Generator.java b/generator/src/main/java/io/github/lonamiwebs/overgram/generator/Generator.java index d22a93d..491b22b 100644 --- a/generator/src/main/java/io/github/lonamiwebs/overgram/generator/Generator.java +++ b/generator/src/main/java/io/github/lonamiwebs/overgram/generator/Generator.java @@ -19,10 +19,10 @@ public class Generator { writeAbstract(writer, types); } try (final Writer writer = new BufferedWriter(new FileWriter(typesFile))) { - writeCode(writer, "Types", null, types, true); + writeCode(writer, "Types", "%s", types, false); } try (final Writer writer = new BufferedWriter(new FileWriter(functionsFile))) { - writeCode(writer, "Functions", "TLRequest", functions, false); + writeCode(writer, "Functions", "TLRequest<%s>", functions, true); } } @@ -50,7 +50,7 @@ public class Generator { private static void writeCode( final Writer writer, final String className, final String extendsName, - final List objects, final boolean generateGetList) throws IOException { + final List objects, final boolean functions) throws IOException { writer.write("package io.github.lonamiwebs.overgram.tl;\n"); writer.write("import io.github.lonamiwebs.overgram.utils.BinaryReader;\n"); writer.write("import io.github.lonamiwebs.overgram.utils.BinaryWriter;\n"); @@ -60,6 +60,7 @@ public class Generator { writer.write("public class "); writer.write(className); writer.write(" {\n"); + final boolean nested = extendsName.contains("<"); for (final Map.Entry> nsObjects : byNamespace(objects).entrySet()) { if (!nsObjects.getKey().isEmpty()) { writer.write("public static class "); @@ -70,12 +71,8 @@ public class Generator { writer.write("public static class "); writer.write(Utils.toCamelCase(object.name, true)); writer.write(" extends "); - if (extendsName == null) { - writer.write("Abstract."); - writer.write(Utils.toCamelCase(object.type, true)); - } else { - writer.write(extendsName); - } + writer.write(String.format(extendsName, object.typeAsArg().javaType(nested))); + writer.write(" {\n"); writer.write("public static final int CONSTRUCTOR_ID = " + object.code + ";\n"); @@ -120,6 +117,9 @@ public class Generator { writeSerialize(writer, object); writeDeserialize(writer, object); + if (functions) { + writeReadResult(writer, object); + } writer.write("}\n"); } @@ -128,7 +128,7 @@ public class Generator { } } - if (generateGetList) { + if (!functions) { writer.write("public static TLObject getFromId(final int id) throws ClassNotFoundException {\n"); writer.write("switch (id) {\n"); @@ -221,66 +221,7 @@ public class Generator { // TODO We don't handle boxed vs. unboxed here, either writer.write(VARIABLE_SUFFIX + i); writer.write(" = "); - if (arg.types.get(0).equalsIgnoreCase("vector")) { - switch (arg.types.get(1)) { - case "int": - writer.write("reader.readIntList();"); - break; - case "long": - writer.write("reader.readLongList();"); - break; - case "string": - writer.write("reader.readStringList();"); - break; - case "bytes": - writer.write("reader.readBytesList();"); - break; - case "int128": - case "int256": - case "double": - case "Bool": - case "true": - throw new UnsupportedOperationException("vector of " + arg.types.get(1)); - default: - writer.write("("); - writer.write(arg.javaType()); - writer.write(") reader.readTlList();"); - break; - } - } else { - switch (arg.types.get(0)) { - case "int": - writer.write("reader.readInt();"); - break; - case "long": - writer.write("reader.readLong();"); - break; - case "int128": - writer.write("reader.readInt128();"); - break; - case "int256": - writer.write("reader.readInt256();"); - break; - case "double": - writer.write("reader.readDouble();"); - break; - case "Bool": - case "true": - writer.write("reader.readBoolean();"); - break; - case "string": - writer.write("reader.readString();"); - break; - case "bytes": - writer.write("reader.readBytes();"); - break; - default: - writer.write("("); - writer.write(arg.javaType()); - writer.write(") reader.readTl();"); - break; - } - } + writeRead(writer, arg); if (arg.flag != null) { writer.write(" }\n"); @@ -291,6 +232,79 @@ public class Generator { writer.write("}\n"); } + private static void writeRead(final Writer writer, final TLArg arg) throws IOException { + if (arg.types.get(0).equalsIgnoreCase("vector")) { + switch (arg.types.get(1)) { + case "int": + writer.write("reader.readIntList();"); + break; + case "long": + writer.write("reader.readLongList();"); + break; + case "string": + writer.write("reader.readStringList();"); + break; + case "bytes": + writer.write("reader.readBytesList();"); + break; + case "int128": + case "int256": + case "double": + case "Bool": + case "true": + throw new UnsupportedOperationException("vector of " + arg.types.get(1)); + default: + writer.write("("); + writer.write(arg.javaType()); + writer.write(") reader.readTlList();"); + break; + } + } else { + switch (arg.types.get(0)) { + case "int": + writer.write("reader.readInt();"); + break; + case "long": + writer.write("reader.readLong();"); + break; + case "int128": + writer.write("reader.readInt128();"); + break; + case "int256": + writer.write("reader.readInt256();"); + break; + case "double": + writer.write("reader.readDouble();"); + break; + case "Bool": + case "true": + writer.write("reader.readBoolean();"); + break; + case "string": + writer.write("reader.readString();"); + break; + case "bytes": + writer.write("reader.readBytes();"); + break; + default: + writer.write("("); + writer.write(arg.javaType()); + writer.write(") reader.readTl();"); + break; + } + } + } + + private static void writeReadResult(final Writer writer, final TLObject object) throws IOException { + writer.write("public "); + writer.write(object.typeAsArg().javaType(true)); + writer.write(" readResult(final BinaryReader reader) throws ClassNotFoundException {\n"); + writer.write("return "); + writeRead(writer, object.typeAsArg()); + writer.write('\n'); + writer.write("}\n"); + } + private static Map> byNamespace(final Iterable objects) { final Map> result = new HashMap<>(); for (final TLObject object : objects) { diff --git a/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLArg.java b/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLArg.java index d65d6f1..9a41bf5 100644 --- a/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLArg.java +++ b/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLArg.java @@ -4,6 +4,7 @@ import io.github.lonamiwebs.overgram.utils.Utils; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class TLArg { public final String name; @@ -11,17 +12,19 @@ public class TLArg { public final boolean flags; public final Flag flag; public final boolean genericDefinition; + public final TLArg genericOn; private TLArg(final String name, final List types, final boolean flags, final Flag flag, - final boolean genericDefinition) { + final boolean genericDefinition, final TLArg genericOn) { this.name = name; this.types = types; this.flags = flags; this.flag = flag; this.genericDefinition = genericDefinition; + this.genericOn = genericOn; } - public static TLArg fromString(String string) { + public static TLArg fromString(final String string, final Map genericDefinitions) { final String[] tmp = string.split(":"); boolean genericDefinition = false; @@ -52,13 +55,38 @@ public class TLArg { } types.add(tmp[1]); - return new TLArg(tmp[0], types, flags, flag, genericDefinition); + final TLArg genericOn; + if (!genericDefinition && types.size() == 1) { + genericOn = genericDefinitions.get(types.get(0)); + } else { + genericOn = null; + } + + return new TLArg(tmp[0], types, flags, flag, genericDefinition, genericOn); + } + + public static TLArg fromUnnamedString(final String string, final Map genericDefinitions) { + return fromString(":" + string, genericDefinitions); } public String javaType() { - final StringBuilder builder = new StringBuilder(); + return javaType(false); + } - boolean nested = false; + public String javaType(boolean nested) { + if (genericOn != null) { + return genericOn.javaType(); + } + + if (genericDefinition) { + if (types.size() == 1 && types.get(0).equals("Type")) { + return "TLObject"; + } else { + throw new UnsupportedOperationException(); + } + } + + final StringBuilder builder = new StringBuilder(); for (final String type : types) { if (type.startsWith("!")) { if (nested) { diff --git a/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLObject.java b/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLObject.java index 472794e..1c4d7c8 100644 --- a/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLObject.java +++ b/generator/src/main/java/io/github/lonamiwebs/overgram/parser/TLObject.java @@ -1,7 +1,9 @@ package io.github.lonamiwebs.overgram.parser; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class TLObject { @@ -11,12 +13,15 @@ public class TLObject { public final int code; public final List args; public final String type; + private final Map genericDefinitions; - private TLObject(final String fullname, final int code, final List args, final String type) { + private TLObject(final String fullname, final int code, final List args, final String type, + final Map genericDefinitions) { this.fullname = fullname; this.code = code; this.args = args; this.type = type; + this.genericDefinitions = genericDefinitions; final String[] nsName = fullname.split("\\."); if (nsName.length == 1) { @@ -47,13 +52,23 @@ public class TLObject { code = tmp.length == 1 ? "0" : tmp[1]; final List args = new ArrayList<>(); + final Map genericDefinitions = new HashMap<>(1); + if (!string.isEmpty()) { for (final String part : string.split(" ")) { - args.add(TLArg.fromString(part)); + final TLArg arg = TLArg.fromString(part, genericDefinitions); + if (arg.genericDefinition) { + genericDefinitions.put(arg.name, arg); + } + args.add(arg); } } - return new TLObject(name, Integer.parseUnsignedInt(code, 16), args, type); + return new TLObject(name, Integer.parseUnsignedInt(code, 16), args, type, genericDefinitions); + } + + public TLArg typeAsArg() { + return TLArg.fromUnnamedString(type, genericDefinitions); } @Override diff --git a/generator/src/main/resources/mtproto_api.tl b/generator/src/main/resources/mtproto_api.tl index 46a5bf5..4d0cb9a 100644 --- a/generator/src/main/resources/mtproto_api.tl +++ b/generator/src/main/resources/mtproto_api.tl @@ -80,7 +80,7 @@ ping#7abe77ec ping_id:long = Pong; ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; destroy_session#e7512126 session_id:long = DestroySessionRes; -http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; +//http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; //test.useGzipPacked = GzipPacked; //test.useServerDhInnerData = Server_DH_inner_data; diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java b/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java index 105cadc..638b731 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java @@ -5,14 +5,15 @@ import io.github.lonamiwebs.overgram.network.connection.Connection; import io.github.lonamiwebs.overgram.tl.*; import io.github.lonamiwebs.overgram.utils.BinaryReader; -import javax.naming.OperationNotSupportedException; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import java.util.concurrent.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; public class MTProtoSender { private final MTProtoState state; @@ -261,7 +262,11 @@ public class MTProtoSender { // TODO RPC error final BinaryReader reader = new BinaryReader(ByteBuffer.wrap(result.result())); - replyMessage.future.complete(((TLRequest) replyMessage.object).readResult(reader)); + try { + replyMessage.future.complete(((TLRequest) replyMessage.object).readResult(reader)); + } catch (ClassNotFoundException e) { + replyMessage.future.completeExceptionally(e); + } } public void handleContainer(final TLMessage message) throws InterruptedException { diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/TLRequest.java b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/TLRequest.java index acb1787..ec48d59 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/TLRequest.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/TLRequest.java @@ -2,6 +2,6 @@ package io.github.lonamiwebs.overgram.tl; import io.github.lonamiwebs.overgram.utils.BinaryReader; -public abstract class TLRequest extends TLObject { - public abstract T readResult(final BinaryReader reader); +public abstract class TLRequest extends TLObject { + public abstract T readResult(final BinaryReader reader) throws ClassNotFoundException; }