Bladeren bron

fix naming and generation

painor 5 jaren geleden
bovenliggende
commit
1e0ac70771

+ 3 - 11
examples/main.js

@@ -6,22 +6,14 @@ const logger = log4js.getLogger('gramjs')
 
 logger.level = 'debug'
 
-const inputPeer = new InputPeerChat({
-    chatId: 400319287,
-    accessHash: 4770003194588524965n,
-})
-const message = new SendMessageRequest({
-    peer: inputPeer,
-    message: 'hi',
-    randomId: 5,
-})
+
 console.log(message.bytes.toString('hex'));
 
 (async () => {
     console.log('Loading interactive example...')
     const sessionName = 'anon'
-    const apiId = 17349
-    const apiHash = '344583e45741c457fe1862106095a5eb'
+    const apiId = -1
+    const apiHash = ''
     const client = new TelegramClient(sessionName, apiId, apiHash)
     await client.connect()
 

+ 171 - 7
gramjs/client/TelegramClient.js

@@ -1,13 +1,13 @@
 const log4js = require('log4js')
 const Helpers = require('../utils/Helpers')
-const errors = require('../errors/rpcerrorlist')
+const errors = require('../errors')
 const { addKey } = require('../crypto/RSA')
 const { TLRequest } = require('../tl/tlobject')
 const Session = require('../sessions/Session')
 const os = require('os')
 const { GetConfigRequest } = require('../tl/functions/help')
 const { LAYER } = require('../tl/AllTLObjects')
-const { functions } = require('../tl')
+const { functions, types } = require('../tl')
 const MTProtoSender = require('../network/MTProtoSender')
 const { ConnectionTCPFull } = require('../network/connection/TCPFull')
 const DEFAULT_DC_ID = 4
@@ -35,16 +35,16 @@ class TelegramClient {
         baseLogger: 'gramjs',
     }
 
+
     constructor(sessionName, apiId, apiHash, opts = TelegramClient.DEFAULT_OPTIONS) {
         if (apiId === undefined || apiHash === undefined) {
             throw Error('Your API ID or Hash are invalid. Please read "Requirements" on README.md')
         }
         const args = { ...TelegramClient.DEFAULT_OPTIONS, ...opts }
-        console.log("actual args are : ",args)
         this.apiId = apiId
         this.apiHash = apiHash
         this._useIPV6 = args.useIPV6
-
+        this._entityCache = new Set()
         if (typeof args.baseLogger == 'string') {
             this._log = log4js.getLogger(args.baseLogger)
         } else {
@@ -56,7 +56,9 @@ class TelegramClient {
             session.setDC(DEFAULT_DC_ID, this._useIPV6 ? DEFAULT_IPV6_IP : DEFAULT_IPV4_IP, DEFAULT_PORT)
         }
         this.floodSleepLimit = args.floodSleepLimit
+        this._eventBuilders = []
 
+        this._phoneCodeHash = {}
         this.session = session
         // this._entityCache = EntityCache();
         this.apiId = parseInt(apiId)
@@ -111,6 +113,7 @@ class TelegramClient {
      * @returns {Promise<void>}
      */
     async connect() {
+
         const connection = new this._connection(this.session.serverAddress
             , this.session.port, this.session.dcId, this._log)
         if (!await this._sender.connect(connection)) {
@@ -137,15 +140,17 @@ class TelegramClient {
 
     async _switchDC(newDc) {
         this._log.info(`Reconnecting to new data center ${newDc}`)
-        const DC = this._getDC(newDc)
-
+        const DC = await this._getDC(newDc)
+        console.log('dc is ?????????')
         this.session.setDC(DC.id, DC.ipAddress, DC.port)
+        console.log('the dc is ', DC)
         // authKey's are associated with a server, which has now changed
         // so it's not valid anymore. Set to None to force recreating it.
         this._sender.authKey.key = null
         this.session.authKey = null
         await this.session.save()
         await this.disconnect()
+        console.log('hayyyyyyyyyy')
         return await this.connect()
     }
 
@@ -159,17 +164,20 @@ class TelegramClient {
     // region Working with different connections/Data Centers
 
     async _getDC(dcId, cdn = false) {
+        console.log('hi dc ?')
         if (!this._config) {
             this._config = await this.invoke(new functions.help.GetConfigRequest())
         }
-
+        console.log('h')
         if (cdn && !this._cdnConfig) {
             this._cdnConfig = await this.invoke(new functions.help.GetCdnConfigRequest())
             for (const pk of this._cdnConfig.publicKeys) {
                 addKey(pk.publicKey)
             }
         }
+        console.log('ok')
         for (const DC of this._config.dcOptions) {
+            console.log(DC)
             if (DC.id === dcId && DC.ipv6 === this._useIPV6 && DC.cdn === cdn) {
                 return DC
             }
@@ -188,6 +196,7 @@ class TelegramClient {
         if (!(request instanceof TLRequest)) {
             throw new Error('You can only invoke MTProtoRequests')
         }
+        console.log('sending request..', request)
         if (request.CONSTRUCTOR_ID in this._floodWaitedRequests) {
             const due = this._floodWaitedRequests[request.CONSTRUCTOR_ID]
             const diff = Math.round(due - new Date().getTime() / 1000)
@@ -208,8 +217,11 @@ class TelegramClient {
         let attempt = 0
         for (attempt = 0; attempt < this._requestRetries; attempt++) {
             try {
+                console.log('sending promise')
                 const promise = this._sender.send(request)
+                console.log(promise)
                 const result = await promise
+                console.log('the res is : ', result)
                 this.session.processEntities(result)
                 this._entityCache.add(result)
                 return result
@@ -234,13 +246,165 @@ class TelegramClient {
                         throw e
                     }
                     await this._switchDC(e.newDc)
+                } else {
+                    throw e
                 }
             }
         }
         throw new Error(`Request was unsuccessful ${attempt} time(s)`)
     }
 
+    async getMe() {
+        const me = (await this.invoke(new functions.users
+            .GetUsersRequest({ id: [new types.InputUserSelf()] })))[0]
+        return me
+    }
+
+    async signIn(args = {
+        phone: null,
+        code: null,
+        password: null,
+        botToken: null,
+        phoneCodeHash: null,
+    }) {
+        let result
+        if (args.phone && !args.code && !args.password) {
+            return await this.sendCodeRequest(args.phone)
+        } else if (args.code) {
+            const { phone, phoneCodeHash } =
+                this._parsePhoneAndHash(args.phone, args.phoneCodeHash)
+            // May raise PhoneCodeEmptyError, PhoneCodeExpiredError,
+            // PhoneCodeHashEmptyError or PhoneCodeInvalidError.
+            result = await this.invoke(new functions.auth.SignInRequest(
+                phone, phoneCodeHash, args.code.toString()))
+        } else if (args.password) {
+            const pwd = await this.invoke(new functions.account.GetPasswordRequest())
+            result = await this.invoke(new functions.auth.CheckPasswordRequest(
+                pwdMod.computeCheck(pwd, args.password),
+            ))
+        } else if (args.botToken) {
+            result = await this.invoke(new functions.auth.ImportBotAuthorizationRequest(
+                {
+                    flags: 0,
+                    botAuthToken: args.botToken,
+                    apiId: this.apiId,
+                    apiHash: this.apiHash,
+                },
+            ))
+        } else {
+            throw new Error('You must provide a phone and a code the first time, ' +
+                'and a password only if an RPCError was raised before.')
+        }
+        return this._onLogin(result.user)
+    }
+
     // endregion
+    async isUserAuthorized() {
+        if (!this._authorized) {
+            try {
+                await this.invoke(new functions.updates.GetStateRequest())
+                this._authorized = true
+            } catch (e) {
+                this._authorized = false
+            }
+        }
+        return this._authorized
+    }
+
+    /**
+     * Callback called whenever the login or sign up process completes.
+     * Returns the input user parameter.
+     * @param user
+     * @private
+     */
+    _onLogin(user) {
+        this._bot = Boolean(user.bot)
+        this._authorized = true
+        return user
+    }
+
+    async sendCodeRequest(phone, forceSMS = false) {
+        let result
+        phone = Helpers.parsePhone(phone) || this._phone
+        let phoneHash = this._phoneCodeHash[phone]
+
+        if (!phoneHash) {
+            try {
+                result = await this.invoke(new functions.auth.SendCodeRequest({
+                    phone: phone,
+                    apiId: this.apiId,
+                    apiHash: this.apiHash,
+                    settings: new types.CodeSettings(),
+                }))
+            } catch (e) {
+                if (e instanceof errors.AuthRestartError) {
+                    return await this.sendCodeRequest(phone, forceSMS)
+                }
+                throw e
+            }
+            this._tos = result.termsOfService
+            this._phoneCodeHash[phone] = phoneHash = result.phoneCodeHash
+        } else {
+            forceSMS = true
+        }
+        this._phone = phone
+        if (forceSMS) {
+            result = await this.invoke(new functions.auth.ResendCodeRequest({
+                phone: phone,
+                phoneHash: phoneHash,
+            }))
+            this._phoneCodeHash[phone] = result.phoneCodeHash
+        }
+        return result
+    }
+
+
+    // event region
+    addEventHandler(callback, event) {
+        this._eventBuilders.append([event, callback])
+    }
+
+    _handleUpdate(update) {
+        this.session.processEntities(update)
+        this._entityCache.add(update)
+
+        if (update instanceof types.Updates || update instanceof types.UpdatesCombined) {
+            // TODO deal with entities
+            for (const u of update.updates) {
+                this._processUpdate(u, update.updates)
+            }
+        } else if (update instanceof types.UpdateShort) {
+
+            this._processUpdate(update.update, null)
+        } else {
+            this._processUpdate(update, null)
+        }
+        this._stateCache.update(update)
+    }
+
+    _processUpdate(update, others, entities) {
+        update._entities = entities || {}
+        const args = {
+            update: update,
+            others: others,
+        }
+        this._dispatchUpdate(args)
+    }
+
+
+    // endregion
+
+    async _dispatchUpdate(args = {
+        update: null,
+        others: null,
+        channelId: null,
+        ptsDate: null,
+    }) {
+        for (const [builder, callback] of this._eventBuilders) {
+            const event = builder.build()
+            await callback(event)
+        }
+    }
 }
 
 module.exports = TelegramClient

+ 23 - 20
gramjs/errors/RPCBaseErrors.js

@@ -7,7 +7,7 @@ class RPCError extends Error {
             'RPCError {0}: {1}{2}'
                 .replace('{0}', code)
                 .replace('{1}', message)
-                .replace('{2}', RPCError._fmtRequest(request))
+                .replace('{2}', RPCError._fmtRequest(request)),
         )
         this.code = code
         this.message = message
@@ -15,7 +15,7 @@ class RPCError extends Error {
 
     static _fmtRequest(request) {
         // TODO fix this
-        return ` (caused by ${request})`
+        return ` (caused by ${request.constructor.name})`
     }
 }
 
@@ -23,8 +23,11 @@ class RPCError extends Error {
  * The request must be repeated, but directed to a different data center.
  */
 class InvalidDCError extends RPCError {
-    code = 303;
-    message = 'ERROR_SEE_OTHER';
+    constructor(request, message, code) {
+        super(request, message, code)
+        this.code = code || 303
+        this.message = message || 'ERROR_SEE_OTHER'
+    }
 }
 
 /**
@@ -33,8 +36,8 @@ class InvalidDCError extends RPCError {
  * notified that the data must be corrected before the query is repeated.
  */
 class BadRequestError extends RPCError {
-    code = 400;
-    message = 'BAD_REQUEST';
+    code = 400
+    message = 'BAD_REQUEST'
 }
 
 /**
@@ -42,8 +45,8 @@ class BadRequestError extends RPCError {
  * to authorized users.
  */
 class UnauthorizedError extends RPCError {
-    code = 401;
-    message = 'UNAUTHORIZED';
+    code = 401
+    message = 'UNAUTHORIZED'
 }
 
 /**
@@ -51,16 +54,16 @@ class UnauthorizedError extends RPCError {
  * someone who has blacklisted the current user.
  */
 class ForbiddenError extends RPCError {
-    code = 403;
-    message = 'FORBIDDEN';
+    code = 403
+    message = 'FORBIDDEN'
 }
 
 /**
  * An attempt to invoke a non-existent object, such as a method.
  */
 class NotFoundError extends RPCError {
-    code = 404;
-    message = 'NOT_FOUND';
+    code = 404
+    message = 'NOT_FOUND'
 }
 
 /**
@@ -68,8 +71,8 @@ class NotFoundError extends RPCError {
  * AUTH_KEY_DUPLICATED which can cause the connection to fail.
  */
 class AuthKeyError extends RPCError {
-    code = 406;
-    message = 'AUTH_KEY';
+    code = 406
+    message = 'AUTH_KEY'
 }
 
 /**
@@ -79,8 +82,8 @@ class AuthKeyError extends RPCError {
  * phone number.
  */
 class FloodError extends RPCError {
-    code = 420;
-    message = 'FLOOD';
+    code = 420
+    message = 'FLOOD'
 }
 
 /**
@@ -89,8 +92,8 @@ class FloodError extends RPCError {
  * storage
  */
 class ServerError extends RPCError {
-    code = 500; // Also witnessed as -500
-    message = 'INTERNAL';
+    code = 500 // Also witnessed as -500
+    message = 'INTERNAL'
 }
 
 /**
@@ -98,8 +101,8 @@ class ServerError extends RPCError {
  * call ``answerCallbackQuery`` will result in this "special" RPCError.
  */
 class TimedOutError extends RPCError {
-    code = 503; // Only witnessed as -503
-    message = 'Timeout';
+    code = 503 // Only witnessed as -503
+    message = 'Timeout'
 }
 
 module.exports = {

+ 9 - 4
gramjs/errors/index.js

@@ -4,7 +4,7 @@
  * @param request the request that caused this error
  * @constructor the RPCError as a Python exception that represents this error
  */
-const { rpcErrorsObject } = require('./rpcerrorlist')
+const { rpcErrorsObject, rpcErrorRe } = require('./RPCErrorList')
 
 function RPCMessageToError(rpcError, request) {
     // Try to get the error by direct look-up, otherwise regex
@@ -12,8 +12,13 @@ function RPCMessageToError(rpcError, request) {
     if (cls) {
         // eslint-disable-next-line new-cap
         return new cls(request)
-    } else {
-        return rpcError.errorMessage
+    }
+    for (const [msgRegex, Cls] of rpcErrorRe) {
+        const m = rpcError.errorMessage.match(msgRegex)
+        if (m) {
+            const capture = m.length === 2 ? parseInt(m[1]) : null
+            return new Cls({ request: request, capture: capture })
+        }
     }
 }
 
@@ -24,5 +29,5 @@ module.exports = {
     ...module.exports,
     ...require('./Common'),
     ...require('./RPCBaseErrors'),
-    ...require('./rpcerrorlist'),
+    ...require('./RPCErrorList'),
 }

+ 18 - 0
gramjs/events/common.js

@@ -0,0 +1,18 @@
+class EventBuilder {
+    constructor(args = {
+            chats: null, blacklistChats: null, func: null,
+        },
+    ) {
+        this.chats = args.chats
+        this.blacklistChats = Boolean(args.blacklistChats)
+        this.resolved = false
+        this.func = args.func
+    }
+
+    build(update, others = null) {
+
+    }
+}
+
+
+module.exports = { EventBuilder }

+ 5 - 0
gramjs/events/index.js

@@ -0,0 +1,5 @@
+class StopPropagation extends Error {
+
+}
+
+module.exports = StopPropagation

+ 0 - 3
gramjs/network/MTProtoPlainSender.js

@@ -19,11 +19,8 @@ class MTProtoPlainSender {
      * @param loggers
      */
     constructor(connection, loggers) {
-        console.log("plz?")
         this._state = new MTProtoState(connection, loggers)
-        console.log("dud?")
         this._connection = connection
-        console.log("ok connection is ",connection)
     }
 
     /**

+ 1 - 5
gramjs/network/MTProtoSender.js

@@ -153,7 +153,6 @@ class MTProtoSender {
      * @returns {Promise<boolean>}
      */
     async connect(connection) {
-        console.log("the connc is : ",connection);
         if (this._user_connected) {
             this._log.info('User is already connected!')
             return false
@@ -265,7 +264,7 @@ class MTProtoSender {
             this._log.info('Not disconnecting (already have no connection)')
             return
         }
-        this._log.info('Disconnecting from %s...', this._connection)
+        this._log.info('Disconnecting from %s...', this._connection.toString())
         this._user_connected = false
         this._log.debug('Closing current connection...')
         await this._connection.disconnect()
@@ -465,8 +464,6 @@ class MTProtoSender {
         if (RPCResult.error) {
             // eslint-disable-next-line new-cap
             const error = RPCMessageToError(RPCResult.error, state.request)
-            console.log('error happen', error)
-
             this._send_queue.append(new RequestState(new MsgsAck({ msgIds: [state.msgId] })))
             state.reject(error)
         } else {
@@ -507,7 +504,6 @@ class MTProtoSender {
     async _handleUpdate(message) {
         if (message.obj.SUBCLASS_OF_ID !== 0x8af52aac) {
             // crc32(b'Updates')
-            // TODO fix this. currently getting an error about this not being defined.
             logger.warn(`Note: ${message.obj.constructor.name} is not an update, not dispatching it`)
             return
         }

+ 0 - 1
gramjs/network/MTProtoState.js

@@ -36,7 +36,6 @@ class MTProtoState {
     constructor(authKey, loggers) {
         this.authKey = authKey
         this._log = loggers
-        console.log("creating state ?");
         this.timeOffset = 0
         this.salt = 0
 

+ 4 - 1
gramjs/network/connection/Connection.js

@@ -44,7 +44,9 @@ class Connection {
     async connect() {
         await this._connect()
         this._connected = true
-        this._sendTask = this._sendLoop()
+        if (!this._sendTask) {
+            this._sendTask = this._sendLoop()
+        }
         this._recvTask = this._recvLoop()
     }
 
@@ -90,6 +92,7 @@ class Connection {
             try {
                 data = await this._recv()
                 if (!data) {
+                    console.log('ended')
                     return
                 }
             } catch (e) {

+ 31 - 21
gramjs/sessions/Session.js

@@ -68,29 +68,35 @@ class Session {
             return new Session()
         }
         const filepath = `${sessionUserId}.session`
+
+
         if (existsSync(filepath)) {
-            const ob = JSON.parse(readFileSync(filepath, 'utf-8'), function(key, value) {
-                if (typeof value == 'string' && value.match(/(\d+)n/)) {
-                    return BigInt(value.slice(0, -1))
-                } else {
-                    return value
-                }
-            })
+            try {
+                const ob = JSON.parse(readFileSync(filepath, 'utf-8'), function(key, value) {
+                    if (typeof value == 'string' && value.match(/(\d+)n/)) {
+                        return BigInt(value.slice(0, -1))
+                    } else {
+                        return value
+                    }
+                })
 
-            const authKey = new AuthKey(Buffer.from(ob.authKey._key.data))
-            const session = new Session(ob.sessionUserId)
-            session._serverAddress = ob.serverAddress
-            session._port = ob.port
-            // this.serverAddress = "localhost";
-            // this.port = 21;
-            session.authKey = authKey
-            session.id = ob.id
-            session.sequence = ob.sequence
-            session.salt = ob.salt // Unsigned long
-            session.timeOffset = ob.timeOffset
-            session.lastMessageId = ob.lastMessageId
-            session.user = ob.user
-            return session
+                const authKey = new AuthKey(Buffer.from(ob.authKey._key.data))
+                const session = new Session(ob.sessionUserId)
+                session._serverAddress = ob.serverAddress
+                session._port = ob.port
+                // this.serverAddress = "localhost";
+                // this.port = 21;
+                session.authKey = authKey
+                session.id = ob.id
+                session.sequence = ob.sequence
+                session.salt = ob.salt // Unsigned long
+                session.timeOffset = ob.timeOffset
+                session.lastMessageId = ob.lastMessageId
+                session.user = ob.user
+                return session
+            } catch (e) {
+                return new Session(sessionUserId)
+            }
         } else {
             return new Session(sessionUserId)
         }
@@ -109,6 +115,10 @@ class Session {
         this.lastMessageId = newMessageId
         return newMessageId
     }
+
+    processEntities(result) {
+        console.log('saving entities')
+    }
 }
 
 module.exports = Session

+ 1 - 0
gramjs_generator/utils.js

@@ -9,6 +9,7 @@ const variableSnakeToCamelCase = (str) => str.replace(
         .replace('_', '')
 )
 
+
 module.exports = {
     snakeToCamelCase,
     variableSnakeToCamelCase,