|
@@ -1,7 +1,8 @@
|
|
|
const fs = require('fs');
|
|
|
const util = require('util');
|
|
|
-const { crc32 } = require('crc');
|
|
|
+const {crc32} = require('crc');
|
|
|
const SourceBuilder = require('../sourcebuilder');
|
|
|
+const {snakeToCamelCase, variableSnakeToCamelCase} = require("../utils");
|
|
|
|
|
|
const AUTO_GEN_NOTICE =
|
|
|
"/*! File generated by TLObjects' generator. All changes will be ERASED !*/";
|
|
@@ -46,11 +47,15 @@ const BASE_TYPES = [
|
|
|
];
|
|
|
|
|
|
// Patched types {fullname: custom.ns.Name}
|
|
|
-const PATCHED_TYPES = {
|
|
|
+
|
|
|
+//No patches currently
|
|
|
+/**
|
|
|
+ const PATCHED_TYPES = {
|
|
|
messageEmpty: 'message.Message',
|
|
|
message: 'message.Message',
|
|
|
messageService: 'message.Message',
|
|
|
-};
|
|
|
+};*/
|
|
|
+const PATCHED_TYPES = {};
|
|
|
|
|
|
const writeModules = (
|
|
|
outDir,
|
|
@@ -60,7 +65,7 @@ const writeModules = (
|
|
|
typeConstructors
|
|
|
) => {
|
|
|
// namespace_tlobjects: {'namespace', [TLObject]}
|
|
|
- fs.mkdirSync(outDir, { recursive: true });
|
|
|
+ fs.mkdirSync(outDir, {recursive: true});
|
|
|
|
|
|
for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
|
|
|
const file = `${outDir}/${ns === 'null' ? 'index' : ns}.js`;
|
|
@@ -91,10 +96,11 @@ const writeModules = (
|
|
|
|
|
|
// Import struct for the .__bytes__(self) serialization
|
|
|
builder.writeln("const struct = require('python-struct');");
|
|
|
+ builder.writeln(`const Helpers = require('../../utils/Helpers');`);
|
|
|
|
|
|
const typeNames = new Set();
|
|
|
const typeDefs = [];
|
|
|
-
|
|
|
+ /*
|
|
|
// Find all the types in this file and generate type definitions
|
|
|
// based on the types. The type definitions are written to the
|
|
|
// file at the end.
|
|
@@ -127,7 +133,7 @@ const writeModules = (
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
+ }*/
|
|
|
|
|
|
const imports = {};
|
|
|
const primitives = new Set([
|
|
@@ -176,7 +182,8 @@ const writeModules = (
|
|
|
}
|
|
|
|
|
|
// Add imports required for type checking
|
|
|
- if (imports) {
|
|
|
+ /**
|
|
|
+ if (imports) {
|
|
|
builder.writeln('if (false) { // TYPE_CHECKING {');
|
|
|
|
|
|
for (const [namespace, names] of Object.entries(imports)) {
|
|
@@ -188,7 +195,7 @@ const writeModules = (
|
|
|
}
|
|
|
|
|
|
builder.endBlock();
|
|
|
- }
|
|
|
+ }*/
|
|
|
|
|
|
// Generate the class for every TLObject
|
|
|
for (const t of tlobjects) {
|
|
@@ -206,9 +213,55 @@ const writeModules = (
|
|
|
for (const line of typeDefs) {
|
|
|
builder.writeln(line);
|
|
|
}
|
|
|
-
|
|
|
writeModuleExports(tlobjects, builder);
|
|
|
+ if (file.indexOf("index.js") > 0) {
|
|
|
+ for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
|
|
|
+ if (ns !== 'null') {
|
|
|
+ builder.writeln("let %s = require('./%s');", ns, ns);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
|
|
|
+ if (ns !== 'null') {
|
|
|
+ builder.writeln("module.exports.%s = %s;", ns, ns);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const writeReadResult = (tlobject, builder) => {
|
|
|
+ // Only requests can have a different response that's not their
|
|
|
+ // serialized body, that is, we'll be setting their .result.
|
|
|
+ //
|
|
|
+ // The default behaviour is reading a TLObject too, so no need
|
|
|
+ // to override it unless necessary.
|
|
|
+ if (!tlobject.isFunction)
|
|
|
+ return;
|
|
|
+
|
|
|
+ // https://core.telegram.org/mtproto/serialize#boxed-and-bare-types
|
|
|
+ // TL;DR; boxed types start with uppercase always, so we can use
|
|
|
+ // this to check whether everything in it is boxed or not.
|
|
|
+ //
|
|
|
+ // Currently only un-boxed responses are Vector<int>/Vector<long>.
|
|
|
+ // If this weren't the case, we should check upper case after
|
|
|
+ // max(index('<'), index('.')) (and if it is, it's boxed, so return).
|
|
|
+ let m = tlobject.result.match(/Vector<(int|long)>/);
|
|
|
+ if (!m) {
|
|
|
+ return
|
|
|
}
|
|
|
+ //builder.endBlock();
|
|
|
+ builder.writeln('readResult(reader){');
|
|
|
+ builder.writeln('reader.readInt(); // Vector ID');
|
|
|
+ builder.writeln('let temp = [];');
|
|
|
+ builder.writeln("let len = reader.readInt(); //fix this");
|
|
|
+ builder.writeln('for (let i=0;i<len;i++){');
|
|
|
+ let read = m[1][0].toUpperCase() + m[1].slice(1);
|
|
|
+ builder.writeln('temp.push(reader.read%s())', read);
|
|
|
+ builder.endBlock();
|
|
|
+ builder.writeln('return temp');
|
|
|
+ builder.endBlock();
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -222,14 +275,17 @@ const writeModules = (
|
|
|
const writeSourceCode = (tlobject, kind, builder, typeConstructors) => {
|
|
|
writeClassConstructor(tlobject, kind, typeConstructors, builder);
|
|
|
writeResolve(tlobject, builder);
|
|
|
- writeToJson(tlobject, builder);
|
|
|
+ //writeToJson(tlobject, builder);
|
|
|
writeToBytes(tlobject, builder);
|
|
|
builder.currentIndent--;
|
|
|
+ writeFromReader(tlobject, builder);
|
|
|
+ writeReadResult(tlobject, builder);
|
|
|
+ builder.currentIndent--;
|
|
|
builder.writeln('}');
|
|
|
- // writeFromReader(tlobject, builder);
|
|
|
- // writeReadResult(tlobject, builder);
|
|
|
+
|
|
|
};
|
|
|
|
|
|
+
|
|
|
const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
|
|
|
builder.writeln();
|
|
|
builder.writeln();
|
|
@@ -248,6 +304,14 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // Note : this is needed to be able to access them
|
|
|
+ // with or without an instance
|
|
|
+ builder.writeln(
|
|
|
+ `static CONSTRUCTOR_ID = 0x${tlobject.id.toString(16).padStart(8, '0')};`
|
|
|
+ );
|
|
|
+ builder.writeln(`static SUBCLASS_OF_ID = 0x${crc32(tlobject.result).toString("16")};`);
|
|
|
+ builder.writeln();
|
|
|
+
|
|
|
builder.writeln('/**');
|
|
|
|
|
|
if (tlobject.isFunction) {
|
|
@@ -278,22 +342,22 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
|
|
|
builder.writeln(
|
|
|
`this.CONSTRUCTOR_ID = 0x${tlobject.id.toString(16).padStart(8, '0')};`
|
|
|
);
|
|
|
- builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(tlobject.result)};`);
|
|
|
+ builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(tlobject.result).toString("16")};`);
|
|
|
builder.writeln();
|
|
|
|
|
|
// Set the arguments
|
|
|
for (const arg of tlobject.realArgs) {
|
|
|
if (!arg.canBeInferred) {
|
|
|
- builder.writeln(`this.${arg.name} = args.${arg.name};`);
|
|
|
+ builder.writeln(`this.${variableSnakeToCamelCase(arg.name)} = args.${variableSnakeToCamelCase(arg.name)};`);
|
|
|
}
|
|
|
|
|
|
- // Currently the only argument that can be
|
|
|
+ // Currently the only argument that can be
|
|
|
// inferred are those called 'random_id'
|
|
|
else if (arg.name === 'random_id') {
|
|
|
// Endianness doesn't really matter, and 'big' is shorter
|
|
|
- let code = `int.from_bytes(os.urandom(${
|
|
|
+ let code = `Helpers.readBigIntFromBuffer(Helpers.generateRandomBytes(${
|
|
|
arg.type === 'long' ? 8 : 4
|
|
|
- }), 'big', signed=True)`;
|
|
|
+ }),false,true)`;
|
|
|
|
|
|
if (arg.isVector) {
|
|
|
// Currently for the case of "messages.forwardMessages"
|
|
@@ -308,7 +372,7 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
|
|
|
}
|
|
|
|
|
|
builder.writeln(
|
|
|
- `this.random_id = random_id !== null ? random_id : ${code}`
|
|
|
+ `this.randomId = args.randomId !== undefined ? args.randomId : ${code};`
|
|
|
);
|
|
|
} else {
|
|
|
throw new Error(`Cannot infer a value for ${arg}`);
|
|
@@ -367,8 +431,8 @@ const writeResolve = (tlobject, builder) => {
|
|
|
builder.endBlock();
|
|
|
}
|
|
|
};
|
|
|
-
|
|
|
-const writeToJson = (tlobject, builder) => {
|
|
|
+/**
|
|
|
+ const writeToJson = (tlobject, builder) => {
|
|
|
builder.writeln('toJson() {');
|
|
|
builder.writeln('return {');
|
|
|
|
|
@@ -411,83 +475,92 @@ const writeToJson = (tlobject, builder) => {
|
|
|
builder.currentIndent--;
|
|
|
builder.writeln('}');
|
|
|
};
|
|
|
-
|
|
|
+ */
|
|
|
const writeToBytes = (tlobject, builder) => {
|
|
|
builder.writeln('get bytes() {');
|
|
|
|
|
|
// Some objects require more than one flag parameter to be set
|
|
|
// at the same time. In this case, add an assertion.
|
|
|
const repeatedArgs = {};
|
|
|
-
|
|
|
- for (const arg of tlobject.args) {
|
|
|
+ for (let arg of tlobject.args) {
|
|
|
if (arg.isFlag) {
|
|
|
if (!repeatedArgs[arg.flagIndex]) {
|
|
|
repeatedArgs[arg.flagIndex] = [];
|
|
|
}
|
|
|
-
|
|
|
repeatedArgs[arg.flagIndex].push(arg);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- for (const ra of Object.values(repeatedArgs)) {
|
|
|
+ for (let ra of Object.values(repeatedArgs)) {
|
|
|
if (ra.length > 1) {
|
|
|
- const cnd1 = ra.map(
|
|
|
- a => `(this.${a.name} || this.${a.name} !== null)`
|
|
|
- );
|
|
|
- const cnd2 = ra.map(
|
|
|
- a => `(this.${a.name} === null || this.${a.name} === false)`
|
|
|
- );
|
|
|
-
|
|
|
- builder.writeln(
|
|
|
- 'if (!(%s || %s)) {',
|
|
|
- cnd1.join(' && '),
|
|
|
- cnd2.join(' && ')
|
|
|
- );
|
|
|
-
|
|
|
- builder.writeln(
|
|
|
- "throw new Error('%s parameters must all be false-y (like null) or all me true-y');",
|
|
|
- ra.map(a => a.name).join(', ')
|
|
|
- );
|
|
|
-
|
|
|
- builder.endBlock();
|
|
|
+ let cnd1 = [];
|
|
|
+ let cnd2 = [];
|
|
|
+ let names = [];
|
|
|
+
|
|
|
+ for (let a of ra) {
|
|
|
+ cnd1.push(`this.${a.name} || this.${a.name}!==null`);
|
|
|
+ cnd2.push(`this.${a.name}===null || this.${a.name}===false`);
|
|
|
+ names.push(a.name);
|
|
|
+ }
|
|
|
+ builder.writeln("if (!((%s) && (%s)))\n\t throw new Error('%s paramaters must all"
|
|
|
+ + " be false-y or all true')", cnd1.join(" && "), cnd2.join(" && "), names.join(", "));
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- const bytes = Buffer.from(
|
|
|
- parseInt(tlobject.id)
|
|
|
- .toString(16)
|
|
|
- .padStart(8, `0`),
|
|
|
- `hex`
|
|
|
- )
|
|
|
- .readUInt32LE()
|
|
|
- .toString(16)
|
|
|
- .padStart(8, `0`);
|
|
|
-
|
|
|
- builder.writeln('return parseInt([');
|
|
|
+ builder.writeln("return Buffer.concat([");
|
|
|
builder.currentIndent++;
|
|
|
- builder.writeln("'%s',", bytes);
|
|
|
-
|
|
|
- for (const arg of tlobject.args) {
|
|
|
+ let b = Buffer.alloc(4);
|
|
|
+ b.writeUInt32LE(tlobject.id, 0);
|
|
|
+ // First constructor code, we already know its bytes
|
|
|
+ builder.writeln('Buffer.from("%s","hex"),', b.toString("hex"));
|
|
|
+ for (let arg of tlobject.args) {
|
|
|
if (writeArgToBytes(builder, arg, tlobject.args)) {
|
|
|
builder.writeln(',');
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- builder.currentIndent--;
|
|
|
- builder.writeln(']);');
|
|
|
+ builder.writeln("])");
|
|
|
builder.endBlock();
|
|
|
+
|
|
|
};
|
|
|
|
|
|
// writeFromReader
|
|
|
+const writeFromReader = (tlobject, builder) => {
|
|
|
+
|
|
|
+ builder.writeln("static fromReader(reader) {");
|
|
|
+ for (const arg of tlobject.args) {
|
|
|
+
|
|
|
+ if (arg.name !== "flag") {
|
|
|
+
|
|
|
+
|
|
|
+ if (arg.name !== "x") {
|
|
|
+
|
|
|
+
|
|
|
+ builder.writeln("let %s", "_" + arg.name + ";");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // TODO fix this really
|
|
|
+ builder.writeln("let _x;");
|
|
|
+ builder.writeln("let len;");
|
|
|
+
|
|
|
+
|
|
|
+ for (const arg of tlobject.args) {
|
|
|
+ writeArgReadCode(builder, arg, tlobject.args, "_" + arg.name);
|
|
|
+ }
|
|
|
+ let temp = [];
|
|
|
+ for (let a of tlobject.realArgs) {
|
|
|
+ temp.push(`${variableSnakeToCamelCase(a.name)}:_${a.name}`)
|
|
|
+ }
|
|
|
+ builder.writeln("return new this({%s})", temp.join(",\n\t"));
|
|
|
+ builder.endBlock();
|
|
|
+};
|
|
|
// writeReadResult
|
|
|
|
|
|
/**
|
|
|
* Writes the .__bytes__() code for the given argument
|
|
|
- * :param builder: The source code builder
|
|
|
- * :param arg: The argument to write
|
|
|
- * :param args: All the other arguments in TLObject same __bytes__.
|
|
|
+ * @param builder: The source code builder
|
|
|
+ * @param arg: The argument to write
|
|
|
+ * @param args: All the other arguments in TLObject same __bytes__.
|
|
|
* This is required to determine the flags value
|
|
|
- * :param name: The name of the argument. Defaults to "self.argname"
|
|
|
+ * @param name: The name of the argument. Defaults to "self.argname"
|
|
|
* This argument is an option because it's required when
|
|
|
* writing Vectors<>
|
|
|
*/
|
|
@@ -495,11 +568,13 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
|
|
|
if (arg.genericDefinition) {
|
|
|
return; // Do nothing, this only specifies a later type
|
|
|
}
|
|
|
-
|
|
|
if (name === null) {
|
|
|
name = `this.${arg.name}`;
|
|
|
}
|
|
|
-
|
|
|
+ if (name =="this.msg_ids"){
|
|
|
+ console.log(name)
|
|
|
+ }
|
|
|
+ name = variableSnakeToCamelCase(name);
|
|
|
// The argument may be a flag, only write if it's not None AND
|
|
|
// if it's not a True type.
|
|
|
// True types are not actually sent, but instead only used to
|
|
@@ -512,18 +587,19 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
|
|
|
// so we need an extra join here. Note that empty vector flags
|
|
|
// should NOT be sent either!
|
|
|
builder.write(
|
|
|
- "%s === null || %s === false ? b'' : b''.join([",
|
|
|
+ "(%s === undefined || %s === false || %s ===null) ? Buffer.alloc(0) :Buffer.concat([",
|
|
|
+ name,
|
|
|
name,
|
|
|
name
|
|
|
);
|
|
|
} else {
|
|
|
- builder.write("%s === null || %s === false ? b'' : [", name, name);
|
|
|
+ builder.write("(%s === undefined || %s === false || %s ===null) ? Buffer.alloc(0) : [", name, name,name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (arg.isVector) {
|
|
|
if (arg.useVectorId) {
|
|
|
- builder.write("'15c4b51c',");
|
|
|
+ builder.write("Buffer.from('15c4b51c','hex'),");
|
|
|
}
|
|
|
|
|
|
builder.write("struct.pack('<i', %s.length),", name);
|
|
@@ -531,7 +607,6 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
|
|
|
// Cannot unpack the values for the outer tuple through *[(
|
|
|
// since that's a Python >3.5 feature, so add another join.
|
|
|
builder.write('Buffer.concat(%s.map(x => ', name);
|
|
|
-
|
|
|
// Temporary disable .is_vector, not to enter this if again
|
|
|
// Also disable .is_flag since it's not needed per element
|
|
|
const oldFlag = arg.isFlag;
|
|
@@ -540,7 +615,7 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
|
|
|
arg.isVector = true;
|
|
|
arg.isFlag = oldFlag;
|
|
|
|
|
|
- builder.write('))', name);
|
|
|
+ builder.write('))');
|
|
|
} else if (arg.flagIndicator) {
|
|
|
// Calculate the flags with those items which are not None
|
|
|
if (!args.some(f => f.isFlag)) {
|
|
@@ -553,9 +628,9 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
|
|
|
.filter(flag => flag.isFlag)
|
|
|
.map(
|
|
|
flag =>
|
|
|
- `(this.${flag.name} === null || this.${
|
|
|
- flag.name
|
|
|
- } === false ? 0 : ${1 << flag.flagIndex})`
|
|
|
+ `(this.${variableSnakeToCamelCase(flag.name)} === undefined || this.${
|
|
|
+ variableSnakeToCamelCase(flag.name)
|
|
|
+ } === false || this.${variableSnakeToCamelCase(flag.name)} === null) ? 0 : ${1 << flag.flagIndex}`
|
|
|
)
|
|
|
.join(' | ')
|
|
|
);
|
|
@@ -564,26 +639,26 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
|
|
|
} else if (arg.type === 'int') {
|
|
|
builder.write("struct.pack('<i', %s)", name);
|
|
|
} else if (arg.type === 'long') {
|
|
|
- builder.write("struct.pack('<q', %s)", name);
|
|
|
+ builder.write("Helpers.readBufferFromBigInt(%s,8,true,true)", name);
|
|
|
} else if (arg.type === 'int128') {
|
|
|
- builder.write("%s.to_bytes(16, 'little', signed=True)", name);
|
|
|
+ builder.write("Helpers.readBufferFromBigInt(%s,16,true,true)", name);
|
|
|
} else if (arg.type === 'int256') {
|
|
|
- builder.write("%s.to_bytes(32, 'little', signed=True)", name);
|
|
|
+ builder.write("Helpers.readBufferFromBigInt(%s,32,true,true)", name);
|
|
|
} else if (arg.type === 'double') {
|
|
|
- builder.write("struct.pack('<d', %s)", name);
|
|
|
+ builder.write("struct.pack('<d', %s.toString())", name);
|
|
|
} else if (arg.type === 'string') {
|
|
|
- builder.write('this.serializeBytes(%s)', name);
|
|
|
+ builder.write('TLObject.serializeBytes(%s)', name);
|
|
|
} else if (arg.type === 'Bool') {
|
|
|
builder.write('%s ? 0xb5757299 : 0x379779bc', name);
|
|
|
} else if (arg.type === 'true') {
|
|
|
// These are actually NOT written! Only used for flags
|
|
|
} else if (arg.type === 'bytes') {
|
|
|
- builder.write('this.serializeBytes(%s)', name);
|
|
|
+ builder.write('TLObject.serializeBytes(%s)', name);
|
|
|
} else if (arg.type === 'date') {
|
|
|
- builder.write('this.serializeDatetime(%s)', name);
|
|
|
+ builder.write('TLObject.serializeDatetime(%s)', name);
|
|
|
} else {
|
|
|
// Else it may be a custom type
|
|
|
- builder.write('bytes(%s)', name);
|
|
|
+ builder.write('%s.bytes', name);
|
|
|
|
|
|
// If the type is not boxed (i.e. starts with lowercase) we should
|
|
|
// not serialize the constructor ID (so remove its first 4 bytes).
|
|
@@ -599,15 +674,133 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
|
|
|
builder.write(']');
|
|
|
|
|
|
if (arg.isVector) {
|
|
|
- builder.write(']');
|
|
|
+ builder.write(')');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+/**
|
|
|
+ * Writes the read code for the given argument, setting the
|
|
|
+ * arg.name variable to its read value.
|
|
|
+ * @param builder The source code builder
|
|
|
+ * @param arg The argument to write
|
|
|
+ * @param args All the other arguments in TLObject same on_send.
|
|
|
+ * This is required to determine the flags value
|
|
|
+ * @param name The name of the argument. Defaults to "self.argname"
|
|
|
+ * This argument is an option because it's required when
|
|
|
+ * writing Vectors<>
|
|
|
+ */
|
|
|
+const writeArgReadCode = (builder, arg, args, name) => {
|
|
|
+ if (arg.genericDefinition) {
|
|
|
+ return // Do nothing, this only specifies a later type
|
|
|
+ }
|
|
|
+ //The argument may be a flag, only write that flag was given!
|
|
|
+ let wasFlag = false;
|
|
|
+ if (arg.isFlag) {
|
|
|
+ // Treat 'true' flags as a special case, since they're true if
|
|
|
+ // they're set, and nothing else needs to actually be read.
|
|
|
+ if (arg.type === "true") {
|
|
|
+ builder.writeln("%s = Boolean(flags & %s);", name, 1 << arg.flagIndex);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ wasFlag = true;
|
|
|
+ builder.writeln("if (flags & %s) {", 1 << arg.flagIndex);
|
|
|
+ // Temporary disable .is_flag not to enter this if
|
|
|
+ // again when calling the method recursively
|
|
|
+ arg.isFlag = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (arg.isVector) {
|
|
|
+ if (arg.useVectorId) {
|
|
|
+ // We have to read the vector's constructor ID
|
|
|
+ builder.writeln("reader.readInt();");
|
|
|
+ }
|
|
|
+ builder.writeln("%s = [];", name);
|
|
|
+ builder.writeln("len = reader.readInt();");
|
|
|
+ builder.writeln('for (let i=0;i<len;i++){');
|
|
|
+
|
|
|
+ // Temporary disable .is_vector, not to enter this if again
|
|
|
+ arg.isVector = false;
|
|
|
+ writeArgReadCode(builder, arg, args, "_x");
|
|
|
+ builder.writeln("%s.push(_x);", name);
|
|
|
+ arg.isVector = true;
|
|
|
+
|
|
|
+ } else if (arg.flagIndicator) {
|
|
|
+ //Read the flags, which will indicate what items we should read next
|
|
|
+ builder.writeln("let flags = reader.readInt();");
|
|
|
+ builder.writeln();
|
|
|
+ } else if (arg.type === "int") {
|
|
|
+ builder.writeln("%s = reader.readInt();", name)
|
|
|
+ } else if (arg.type === "long") {
|
|
|
+ builder.writeln("%s = reader.readLong();", name);
|
|
|
+ } else if (arg.type === "int128") {
|
|
|
+ builder.writeln('%s = reader.readLargeInt(128);', name);
|
|
|
+ } else if (arg.type === "int256") {
|
|
|
+ builder.writeln('%s = reader.readLargeInt(256);', name);
|
|
|
+ } else if (arg.type === "double") {
|
|
|
+ builder.writeln('%s = reader.readDouble();', name);
|
|
|
+ } else if (arg.type === "string") {
|
|
|
+ builder.writeln('%s = reader.tgReadString();', name);
|
|
|
+ } else if (arg.type === "Bool") {
|
|
|
+ builder.writeln('%s = reader.tgReadBool();', name);
|
|
|
+ } else if (arg.type === "true") {
|
|
|
+ builder.writeln('%s = true;', name);
|
|
|
+ } else if (arg.type === "bytes") {
|
|
|
+ builder.writeln('%s = reader.tgReadBytes();', name);
|
|
|
+ } else if (arg.type === "date") {
|
|
|
+ builder.writeln('%s = reader.tgReadDate();', name);
|
|
|
+ } else {
|
|
|
+ // Else it may be a custom type
|
|
|
+ if (!arg.skipConstructorId) {
|
|
|
+ builder.writeln('%s = reader.tgReadObject();', name);
|
|
|
+ } else {
|
|
|
+ // Import the correct type inline to avoid cyclic imports.
|
|
|
+ // There may be better solutions so that we can just access
|
|
|
+ // all the types before the files have been parsed, but I
|
|
|
+ // don't know of any.
|
|
|
+ let sepIndex = arg.type.indexOf(".");
|
|
|
+ let ns, t;
|
|
|
+ if (sepIndex === -1) {
|
|
|
+ ns = ".";
|
|
|
+ t = arg.type;
|
|
|
+ } else {
|
|
|
+ ns = "." + arg.type.slice(0, sepIndex);
|
|
|
+ t = arg.type.slice(sepIndex + 1);
|
|
|
+ }
|
|
|
+ let className = snakeToCamelCase(t);
|
|
|
+
|
|
|
+ // There would be no need to import the type if we're in the
|
|
|
+ // file with the same namespace, but since it does no harm
|
|
|
+ // and we don't have information about such thing in the
|
|
|
+ // method we just ignore that case.
|
|
|
+ builder.writeln('let %s = require("%s");', className, ns);
|
|
|
+ builder.writeln("%s = %s.fromReader(reader);", name, className);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // End vector and flag blocks if required (if we opened them before)
|
|
|
+ if (arg.isVector) {
|
|
|
+ builder.writeln("}");
|
|
|
+
|
|
|
+ }
|
|
|
+ if (wasFlag) {
|
|
|
+ builder.endBlock();
|
|
|
+ builder.writeln("else {");
|
|
|
+ builder.writeln("%s = null", name);
|
|
|
+ builder.endBlock();
|
|
|
+ // Restore .isFlag;
|
|
|
+ arg.isFlag = true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
const writePatched = (outDir, namespaceTlobjects) => {
|
|
|
- fs.mkdirSync(outDir, { recursive: true });
|
|
|
+
|
|
|
+ fs.mkdirSync(outDir, {recursive: true});
|
|
|
|
|
|
for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
|
|
|
const file = `${outDir}/${ns === 'null' ? 'index' : ns}.js`;
|
|
@@ -617,6 +810,8 @@ const writePatched = (outDir, namespaceTlobjects) => {
|
|
|
builder.writeln(AUTO_GEN_NOTICE);
|
|
|
builder.writeln("const struct = require('python-struct');");
|
|
|
builder.writeln(`const { TLObject, types, custom } = require('..');`);
|
|
|
+ builder.writeln(`const Helpers = require('../../utils/Helpers');`);
|
|
|
+
|
|
|
builder.writeln();
|
|
|
|
|
|
for (const t of tlobjects) {
|
|
@@ -625,18 +820,23 @@ const writePatched = (outDir, namespaceTlobjects) => {
|
|
|
t.className,
|
|
|
PATCHED_TYPES[t.fullname]
|
|
|
);
|
|
|
-
|
|
|
+ builder.writeln(`static CONSTRUCTOR_ID = 0x${t.id.toString(16)}`);
|
|
|
+ builder.writeln(`static SUBCLASS_OF_ID = 0x${crc32(t.result).toString("16")}`);
|
|
|
+ builder.writeln();
|
|
|
builder.writeln('constructor() {');
|
|
|
builder.writeln('super();');
|
|
|
builder.writeln(`this.CONSTRUCTOR_ID = 0x${t.id.toString(16)}`);
|
|
|
- builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(t.result)}`);
|
|
|
+ builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(t.result).toString("16")}`);
|
|
|
+
|
|
|
builder.endBlock();
|
|
|
|
|
|
- writeToJson(t, builder);
|
|
|
+ //writeToJson(t, builder);
|
|
|
writeToBytes(t, builder);
|
|
|
- // writeFromReader(t, builder);
|
|
|
+ writeFromReader(t, builder);
|
|
|
|
|
|
builder.writeln();
|
|
|
+ builder.endBlock();
|
|
|
+ builder.currentIndent = 0;
|
|
|
builder.writeln(
|
|
|
'types.%s%s = %s',
|
|
|
t.namespace ? `${t.namespace}.` : '',
|
|
@@ -648,7 +848,7 @@ const writePatched = (outDir, namespaceTlobjects) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-const writeAllTlobjects = (tlobjects, layer, builder) => {
|
|
|
+const writeAllTLObjects = (tlobjects, layer, builder) => {
|
|
|
builder.writeln(AUTO_GEN_NOTICE);
|
|
|
builder.writeln();
|
|
|
|
|
@@ -687,11 +887,13 @@ const writeAllTlobjects = (tlobjects, layer, builder) => {
|
|
|
builder.endBlock(true);
|
|
|
};
|
|
|
|
|
|
-const generateTlobjects = (tlobjects, layer, importDepth, outputDir) => {
|
|
|
+const generateTLObjects = (tlobjects, layer, importDepth, outputDir) => {
|
|
|
+ // Group everything by {namespace :[tlobjects]} to generate index.js
|
|
|
const namespaceFunctions = {};
|
|
|
const namespaceTypes = {};
|
|
|
const namespacePatched = {};
|
|
|
|
|
|
+ // Group {type: [constructors]} to generate the documentation
|
|
|
const typeConstructors = {};
|
|
|
|
|
|
for (const tlobject of tlobjects) {
|
|
@@ -743,10 +945,10 @@ const generateTlobjects = (tlobjects, layer, importDepth, outputDir) => {
|
|
|
const stream = fs.createWriteStream(filename);
|
|
|
const builder = new SourceBuilder(stream);
|
|
|
|
|
|
- writeAllTlobjects(tlobjects, layer, builder);
|
|
|
+ writeAllTLObjects(tlobjects, layer, builder);
|
|
|
};
|
|
|
|
|
|
-const cleanTlobjects = outputDir => {
|
|
|
+const cleanTLObjects = outputDir => {
|
|
|
for (let d in ['functions', 'types', 'patched']) {
|
|
|
d = `${outputDir}/d`;
|
|
|
|
|
@@ -763,6 +965,7 @@ const cleanTlobjects = outputDir => {
|
|
|
};
|
|
|
|
|
|
const writeModuleExports = (tlobjects, builder) => {
|
|
|
+
|
|
|
builder.writeln('module.exports = {');
|
|
|
|
|
|
for (const t of tlobjects) {
|
|
@@ -774,6 +977,6 @@ const writeModuleExports = (tlobjects, builder) => {
|
|
|
};
|
|
|
|
|
|
module.exports = {
|
|
|
- generateTlobjects,
|
|
|
- cleanTlobjects,
|
|
|
+ generateTLObjects,
|
|
|
+ cleanTLObjects,
|
|
|
};
|