skip to Main Content

I have a service that use GramJS. In this service I tried to initialize a connection to telegram using GramJS library. Upon running the code I got this error:

[2024-04-19 15:10:02] (node:11888) UnhandledPromiseRejectionWarning: Error: Connection should be a class not an instance
    at new TelegramBaseClient (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newnode_modulestelegramclienttelegramBaseClient.js:84:19)
    at new TelegramClient (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newnode_modulestelegramclientTelegramClient.js:63:9)
    at Command.callback (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newdistlibappExternalServicestelegramExternalService.js:108:35)
    at normal_reply (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newnode_modulesredisindex.js:654:21)
    at RedisClient.return_reply (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newnode_modulesredisindex.js:752:9)
    at JavascriptRedisParser.returnReply (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newnode_modulesredisindex.js:137:18)
    at JavascriptRedisParser.execute (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newnode_modulesredis-parserlibparser.js:544:14)
    at Socket.<anonymous> (C:Usersr.trisnosaputraDocumentsACM-NEWtelegram-notification-backend-newnode_modulesredisindex.js:218:27)
    at Socket.emit (events.js:400:28)
    at addChunk (internal/streams/readable.js:293:12)
[2024-04-19 15:10:02] (node:11888) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
[2024-04-19 15:10:02] (node:11888) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
[2024-04-19 15:10:02] Schedule not found!

Here is the code:

import * as telethon from "telegram";
import { StringSession } from "telegram/sessions";
import { Config } from "../config";
import { Api } from "telegram";
import { IDI } from "../../interface";
import { TelegramClientDto } from "../../dto";
import { Hash } from "../helper";
import { ConnectionTCPObfuscated } from "telegram/network";

export default class TelegramExternalService {
    public client: TelegramClientDto;
    private config: Config;
    private static di: IDI = null;
    private static isReady = false;
    private static recommendedDc: {
        id: number;
        ipAddress: string;
        port: number;
    } = null;

    private static sessions: {
        [phoneNumber: string]: TelegramClientDto
    } = {};

    public static get ready(): boolean {
        return TelegramExternalService.isReady;
    }

    public static setDI(di: IDI): void {
        if (this.di !== null) {
            throw new Error("TelegramExternalService.setDI cannot be called twice");
        }
        this.di = di;
    }

    public static getSession(phoneNumber: string): TelegramClientDto {
        if (this.sessions[phoneNumber] && this.sessions[phoneNumber].connected) {
            return this.sessions[phoneNumber];
        }
    }
    
    public static async startSession(phoneNumber: string): Promise<{token?: string; status: string;}> {
        const telegramExternalService =  new TelegramExternalService();
        if (this.sessions[phoneNumber] && this.sessions[phoneNumber].connected) {
            telegramExternalService.client = this.sessions[phoneNumber];
            return({status: "LOGIN_SUCCESS"});
        }

        await telegramExternalService.initializeSession(phoneNumber);

        try {
            const status = await telegramExternalService.initializeConnection(phoneNumber);
            if (status) {
                return({status: "LOGIN_SUCCESS"});
            }

            console.log(status);
    
            const token = Hash.encode(phoneNumber);
            TelegramExternalService.di.redis.setex(`/phone/${phoneNumber}/token`, 999, token);
            return({status: "SEND_PHONE_CODE", token});
        } catch (e) {
            console.log(e);
            return {status: e.message};
        }
    }
    
    private static async getRecommendedDc(config) {
        if (TelegramExternalService.recommendedDc !== null) {
            return TelegramExternalService.recommendedDc;
        }
        
        let recommendedDc;
        const client = new telethon.TelegramClient(new StringSession(""), config.appAPIId, config.appAPIHash, {
            useIPV6: false,
            connectionRetries: 1
        });

        if (config.telegramEnvironment === "test") {
            recommendedDc = {
                id: 2,
                ipAddress: "149.154.167.40",
                port: 443
            };
        } else {
            console.log("Connecting...");
            await client.connect();
            console.log("Done connecting...");
            const nearestDc = await client.invoke(new Api.help.GetNearestDc());
            const connectionConfig = await client.invoke(new Api.help.GetConfig());
            await client.destroy();

            recommendedDc = connectionConfig.dcOptions.find(dc => dc.id === nearestDc.nearestDc && !dc.ipv6);
        }

        TelegramExternalService.recommendedDc = recommendedDc;
        return recommendedDc;
    }
    
    private constructor() {
        this.config = new Config();
    }

    private initializeSession(phoneNumber: string): Promise<void> {
        return new Promise((resolve) => {
            if (TelegramExternalService.sessions[phoneNumber]) {
                this.client = TelegramExternalService.sessions[phoneNumber];
                console.log(`[${phoneNumber}] uses exising connection`);
                resolve();
            } else {
                console.log(`[${phoneNumber}] attemps to create new connection`);
                TelegramExternalService.di.redis.get(`sessions/${phoneNumber}`, async (err, sessionString) => {
                    let session: StringSession;
                    if (sessionString) {
                        console.log(`[${phoneNumber}] has saved session`);
                        session = new StringSession(sessionString);
                    } else {
                        console.log(`[${phoneNumber}] has no saved session`);
                        session = new StringSession("");
                    }

                    this.client = new telethon.TelegramClient(session, this.config.appAPIId, this.config.appAPIHash, {
                        useIPV6: false,
                        connectionRetries: 1,
                        connection: this.config.telegramEnvironment === "test" ? undefined : ConnectionTCPObfuscated
                    });
                    resolve();
                });
            }
        });
    }

    private initializeConnection(phoneNumber: string): Promise<boolean> {
        return new Promise((async (initialized, failedToInitialize) => {
            const eventName = `/phone/${phoneNumber}/applyCode`;
            const recommendedDc = await TelegramExternalService.getRecommendedDc(this.config);
            console.log("recommendedDc", recommendedDc);
            this.client.session.setDC(recommendedDc.id, recommendedDc.ipAddress, recommendedDc.port);

            try {
                // @ts-ignore
                await this.client.start({
                    phoneNumber: phoneNumber,
                    onError: (e) => {
                        TelegramExternalService.di.redis.emit(`/phone/${phoneNumber}/applyCode/callback`, "false");
                        console.log(e);
                    },
                    phoneCode: () => new Promise((sendPhoneCode) => {
                        console.log(`Try to listening on event [${eventName}]`);
                        console.log(`Connected to ${this.client.session.dcId}`);
                        console.log("HEY! WHeRE IS YOUR CODE?");
                        TelegramExternalService.di.redis.once(eventName, (phoneCode) => {
                            console.log(`Phone code of ${phoneNumber} is ${phoneCode}`);
                            sendPhoneCode(phoneCode);
                        });
                        
                        console.log(`Listening on event [${eventName}]`);
                        initialized(false);
                    }),
                });

                console.log(`Phone number [${phoneNumber}] is ready`);
                TelegramExternalService.di.redis.emit(`/phone/${phoneNumber}/applyCode/callback`, "true");

                const currentUser = await this.client.getMe();
                TelegramExternalService.sessions[phoneNumber] = this.client;
                TelegramExternalService.sessions[phoneNumber].currentUser = currentUser as any;
                this.client.currentUser = currentUser as any;

                console.log(currentUser);
                console.log("Connected to ",  this.client.session.serverAddress);
                this.client.session.save();
                const session = this.client.session.serverAddress;
                if (session) {
                    const key = `sessions/${phoneNumber}`;
                    TelegramExternalService.di.redis.setex(key, 999, session);
                    TelegramExternalService.di.redis.persist(key);
                }
                TelegramExternalService.isReady = true;
                console.log(session);

                initialized(true);
            } catch (e) {
                console.log(e);
                failedToInitialize(e);
            }
        }));
    }
}

Anyone knows how to fix the error?

I hope to fix the error in the code.

2

Answers


  1. The problem is that your undefined connection value is overwriting the defaults and leading to a false-positive.

    From the telegramBaseClient source code

    const clientParamsDefault = {
      connection: isNode ? ConnectionTCPFull : ConnectionTCPObfuscated,
    
    // ...
    
    clientParams = { ...clientParamsDefault, ...clientParams };
    
    // ...
    
    if (!(clientParams.connection instanceof Function)) {
      throw new Error("Connection should be a class not an instance");
    }
    

    A quick demonstration shows the problem

    class Connection {};
    const defaults = { connection: Connection };
    let params = { connection: undefined };
    
    params = { ...defaults, ...params };
    console.log('params', params);
    console.log('Connection is a function?', defaults.connection instanceof Function);
    console.log('params.connection is function?', params.connection instanceof Function);

    The Gram.js code could be better and check for undefined values but it doesn’t. The solution here is to not set a value at all for your test environment

    const params = {
      useIPV6: false,
      connectionRetries: 1,
    };
    if (this.config.telegramEnvironment !== "test") {
      params.connection = ConnectionTCPObfuscated;
    }
    this.client = new telethon.TelegramClient(
      session,
      this.config.appAPIId,
      this.config.appAPIHash,
      params,
    );
    
    Login or Signup to reply.
  2. Not sure if this is what you need?

    import { TelegramClient } from 'telegram';
    import { StringSession } from 'telegram/sessions';
    import { ConnectionTCPObfuscated } from 'telegram/network';
    
    // Example of correct instantiation of TelegramClient with a class reference for connection
    const client = new TelegramClient(new StringSession(''), 12345, 'your_api_hash', {
      connection: ConnectionTCPObfuscated
    });
    
    console.log('Client created with ConnectionTCPObfuscated class:', client);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search