tgsnake / core

core library for tgsnake for connecting to telegram api
https://deno.land/x/tgsnake_core
MIT License
12 stars 1 forks source link

Why session not saving automatic? #7

Closed Jobians closed 2 months ago

butthx commented 2 months ago

Hi, Thank you for opening this issue. Regarding this, can you tell what session you are using? It you use tgsnake it will automatically saved when you kill the app (CTRL + C).

Jobians commented 2 months ago
const storeSession = new Storages.StringSession('bot_session');

Other packages will prompt me to login if not exist but I got

/node_modules/@tgsnake/core/lib/src/storage/StringSession.js:71                                                   throw new Error(`Invalid String Session`);                                                                      ^                          
Error: Invalid String Session                            at new StringSession
butthx commented 2 months ago

Hi, a little clarification, string session is not same store session. String session is string which can be used to log in, it will look like:

BVw2QwAAF1......AcmRAA

You can use string from Telethon, Pyrogram, GramJS.

Another option you can use is RedisSession.

Regarding the error, i see you didn't enter the correct string. Instead of the string session, you fill it with the session name (bot_session). This why error happens.

Jobians commented 2 months ago

Ok you only support string session?

Jobians commented 2 months ago

Also this not available

await client.connect()
await client.checkAuthorization()
butthx commented 2 months ago

Ok you only support string session?

We support Redis based session and File based session. For file based session you can import from tgsnake. You can also create your own sessions by extending the BaseSession class.

Also this not available

await client.connect()
await client.checkAuthorization()

Next version I have added client.connect I will push the latest update to NPM soon after doing some testing. To check authorization, we don't have it. To check whether the user is authorized or not you can do get me if it is successful then the user is authorized.

If you have further questions, you can contact me personally or in the group: https://t.me/tgsnakechat

Jobians commented 2 months ago

My problem is I don't want to be logging in everytime I run the script

butthx commented 2 months ago

If you use string session, you can export it and reuse it. You will not be asked to log in again after that.


import { Client, Raw, Storages } from '@tgsnake/core';
process.env.LOGLEVEL = 'debug'; // set log level, see @tgsnake/log for more information.
const client = new Client(
  // you can fill with Telethon or Pyrogram string session.
  new Storages.StringSession(''),
  apiHash,
  apiId,
);

(async () => {
  // if you already pass the string session, don't fill any arguments in start function, leave it empty.

  await client.start({
    botToken: '', // if you want login as bot, you can login as user too.
    /* Remove "botToken" if you want to login as user.
    phoneNumber : async () => {}, // Phone number with international phone code (include plus sign (+)) will be used to login, the return of function must be a string.
    code : async () => {}, // OTP code, the return of function must be a string.
    password : async () => {}, // if you account has 2FA, the return of function must be a string.
    authError : async (error) => {} // when error BadRequest attempt, this function will be running.
    */
  });
  // exporting session
  console.log(await client.exportSession())
})();

Then in your terminal will be show string session like:

BVw2QwAAF1......AcmRAA

You can use it to prevent re-login every time.

new Storages.StringSession('BVw2QwAAF1......AcmRAA')
Jobians commented 2 months ago
async function startTelegramClient(page) {
  const storeSession = new Storages.StringSession('bot_session');

  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  console.log("Starting Telegram client...");

  const client = new Client(
    storeSession,
    apiHash,
    apiId,
  );

  try {
    await client.start({
      phoneNumber: async () => phoneNumber,
      password: async () => password,
      code: async () =>
        new Promise((resolve) =>
          rl.question("Please enter the code you received: ", resolve)
        ),
      authError: (err) => console.log("Error during authorization:", err),
    });

    const exported = await client.exportSession();
    console.log(exported);
    console.log("Telegram client is ready and listening for new messages...");

    // Register event handler for new messages
    client.addEventHandler(
      async (event) => {
        if (event.isChannel) {
          const message = event.message.message;
        }
      },
      new NewMessage({ fromUsers: [signalChannel] })
    );

  } catch (error) {
    console.log("An error occurred:", error);
  }
}
butthx commented 2 months ago

Invalid string session, you must pass it with blank string or string generated from client.exportSession

- const storeSession = new Storages.StringSession('bot_session');
+ const storeSession = new Storages.StringSession(''); 

Invalid handler, we don't have client.addEventHandler but we have client.addHandler.

-     client.addEventHandler(
-      async (event) => {
-        if (event.isChannel) {
-          const message = event.message.message;
-        }
-      },
-      new NewMessage({ fromUsers: [signalChannel] })
-    );
+    client.addHandler(
+      async (update) => {
+        console.log(update)
+      }
+    );

As with the first aim, this framework was formed so that it is not binding and frees users to be creative. As the name, 'core' means only basic features are available. Basically this framework was created as the basis for tgsnake. It's better to use tgsnake if you want it simpler.

Jobians commented 2 months ago

tgsnake is for telegram bot

butthx commented 2 months ago

tgsnake is for telegram bot

No, You are wrong. Tgsnake can be used to log in as a user or bot. Tgsnake is not using bot api, it using MTProto.

Jobians commented 2 months ago

WTF bro?

const client = new Snake({
    apiHash,
    apiId,
    logLevel: 'none',
    login: {
      sessionName: 'session',
      forceDotSession: true,
    },
  });

Where to pass phone number and password

butthx commented 2 months ago

Where to pass phone number and password

Running your client, it will automatically ask the login information.

Jobians commented 2 months ago

I can't pass it directly?

butthx commented 2 months ago

@Jobians yes, but it is a nice idea.. I'll add it in the next update..

Jobians commented 2 months ago

Screenshot_2024-08-08-13-42-57-26_84d3000e3f4017145260f7618db1d683

const client = new Snake({
    apiHash,
    apiId,
    logLevel: 'none',
    login: {
      sessionName: 'session',
      forceDotSession: true,
    },
    clientOptions: {
      phoneNumber: async () => phoneNumber,
      password: async () => password,
      code: async () =>
        new Promise((resolve) =>
          rl.question("Please enter the code you received: ", resolve)
        ),
      authError: (err) => console.log("Error during authorization:", err),
    },
  });
butthx commented 2 months ago

select the login option, bot for login as bot, user for login as user. For NewMessage error, it not a mistake on the framework side >>.

Jobians commented 2 months ago

So now not possible to pass phone number and password directly?

butthx commented 2 months ago

for clientOptions you can found on: https://tgsnake.js.org/en/guide/client-options

butthx commented 2 months ago

So now not possible to pass phone number and password directly?

yes.

Jobians commented 2 months ago

But it available in @tgsnake/core

butthx commented 2 months ago

But it available in @tgsnake/core

Yes, it is available in @tgsnake/core but we have implemented it in tgsnake using the input terminal. Why do you want to pass phone number and password directly? You still can login as user without pass phone number and password directly. For now, if you really really want to pass phone number and password directly you can build a login plugin.

const { Clients, Client } = require('@tgsnake/core');

function myPlugin(api){
  api.addEventHandler('onLogin', async (app) => {
    app._client = new Client(
      app._options.login.session,
      app._options.apiHash,
      app._options.apiId,
      app._options.clientOptions
    )
    await app._options.login.session.load();
    if(!app._options.login.session?.authKey && app._options.login?.session.userId === undefined){
      const user = await app._client.start({
        phoneNumber, password, code
      })
      await app._options.login.session.save()
      return user
    } else {
      await Clients.Session.connect(app._client)
      return await Clients.Auth.getMe(app._client)
    }
  })
}

usage:

const client = new Snake({
    apiHash,
    apiId,
    logLevel: 'none',
    login: {
      sessionName: 'session',
      forceDotSession: true,
    },
    clientOptions: {},
    plugins: [myPlugin]
  });

Plugin Documentation: https://tgsnake.js.org/en/guide/create-plugin

Jobians commented 2 months ago

Ok thanks brother ♥️

butthx commented 2 months ago

Your welcome, If you need further help, you can open an issue or ask in our Telegram group.

Have a nice day!

Jobians commented 2 months ago

Hope you implement it in future 😁🤝

Jobians commented 2 months ago

Please how to process only my channel update "@mychacnnel"

client.addHandler((update) => {
      let fupdate = update.updates;
      console.log('Update is an array:', fupdate);
console.log('Length of update array:', fupdate.length);

if (fupdate.length > 0) {
  console.log('First item in update array:', fupdate[0]);
} else {
  console.log('The update array is empty.');
}
}

Update is an array: [ { : 'UpdateNewChannelMessage', message: { : 'Message', out: false, mentioned: false, mediaUnread: false, silent: false, post: true, fromScheduled: false, legacy: false, editHide: false, pinned: false, noforwards: false, invertMedia: false, offline: false, id: 29662, peerId: [Object], date: 1723129022, message: 'Helleo channel', entities: [], views: 1, forwards: 0, restrictionReason: [] }, pts: 31316, ptsCount: 1 } ] Length of update array: 1 First item in update array: { : 'UpdateNewChannelMessage', message: { : 'Message', out: false, mentioned: false, mediaUnread: false, silent: false, post: true, fromScheduled: false, legacy: false, editHide: false, pinned: false, noforwards: false, invertMedia: false, offline: false, id: 29662, peerId: { _: 'PeerChannel', channelId: 2187072029n }, date: 1723129022, message: 'G Message ok', entities: [], views: 1, forwards: 0, restrictionReason: [] }, pts: 31316, ptsCount: 1 } Update is an array: undefined /root/betbot/src/telegram/app.js:52 console.log('Length of update array:', fupdate.length); ^ TypeError: Cannot read properties of undefined (reading 'length')

Jobians commented 2 months ago

I finally code it

client.addHandler((update) => {
      if (update instanceof Raw.Updates || update instanceof Raw.UpdatesCombined) {
        const { updates, chats, users } = update;
        for (const _update of updates) {
          if (_update instanceof Raw.UpdateNewChannelMessage){
            for (const _chat of chats) {
              if (_chat.username === signalChannel) {
                const _message = _update.message.message;
                console.log(_message);
              }
            }
          }
        }
      }
    });