Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send message as a bot directly to the user (define user access_hash)? #12

Closed
volodalexey opened this issue Dec 12, 2018 · 11 comments
Closed
Labels
Enhancement 🆕 New feature or request question ❔ Further information is requested

Comments

@volodalexey
Copy link
Contributor

I initialized bot:

const airgram = new Airgram({ id: ..., hash: ..., token: ... });
const { auth, updates } = airgram;
airgram.use(auth);
airgram.use(updates);

airgram.updates.on('updateNewMessage', someNewMessageHandler);

await airgram.updates.startPolling();

Then I run bot and listen to messages from users.
If user send direct message to the bot I see following in update:

{ _: 'message',
  pFlags: {},
  flags: 384,
  id: 564,
  from_id: 123456789,
  to_id: { _: 'peerUser', user_id: 999999999 },
  date: 1544611238,
  message: '/start',
  entities: [ { _: 'messageEntityBotCommand', offset: 0, length: 6 } ] }

where from_id - id of user that sent message
to_id.user_id - id of current bot

And I want to send some response message back to the user, however I can not do this:

// somewhere in someNewMessageHandler()
  ctx.client.messages.sendMessage({
    peer: { _: 'inputPeerUser', user_id: 123456789, access_hash: ... },
    message: 'response',
    random_id: Date.now(),
  })

because I do not know (as a bot) user access_hash. However user started conversation with bot first, so (as a bot) I must be able to get access_hash from this user.
I found answer to load dialogs, but as a bot I can not use this endpoint and I get:

ctx.client.messages.getDialogs()
...
processMessageAck() Rpc error CODE#400 BOT_METHOD_INVALID {}

How can I get user access_hash as a bot?

@esindger
Copy link
Collaborator

You usually can obtain access_hash from the users field of some updates.

import { ag, api } from 'airgram'

airgram.updates.use((ctx: ag.UpdateContext<any>, next) => {
  if ('users' in ctx.update) {
    ctx.update.users.forEach((user: api.UserUnion) => {
       // save user.access_hash to somewhere
    })
  }
  return next()
});

@esindger esindger added the question ❔ Further information is requested label Dec 12, 2018
@volodalexey
Copy link
Contributor Author

Ok. Got it.
I get full updates event, that includes updateNewMessage.
Full updates event object:

{ _: 'updates',
  updates:
   [ { _: 'updateNewMessage',
       message: [Object],
       pts: 570,
       pts_count: 1 } ],
  users:
   [ { _: 'user',
       pFlags: {},
       flags: 4194411,
       id: 123456789,
       access_hash: '999999...999',
       first_name: '...',
       username: '...',
       photo: [Object],
       status: [Object],
       lang_code: 'ru' },
     { _: 'user',
       pFlags: [Object],
       flags: 17419,
       self: true,
       bot: true,
       id: 999999999,
       access_hash: '999999...999',
       first_name: '...',
       username: '...',
       bot_info_version: 1 } ],
  chats: [],
  date: 1544620388,
  seq: 0 }

@volodalexey
Copy link
Contributor Author

@esindger If I do not want to use all updates middleware, but only updateNewMessage, in ctx.update I get only "nested update":

{ _: 'updateNewMessage',
       message: [Object],
       pts: 570,
       pts_count: 1 }

However full update event is:

{ _: 'updates',
  updates:
   [ { _: 'updateNewMessage',
       message: [Object],
       pts: 570,
       pts_count: 1 } ],
  users:
   [ { _: 'user', ... },
     { _: 'user', ... } ], }

Is it possible to get access to "full" update event inside updateNewMessage handler?
E.g. ctx.client.a.b.c.fullUpdateEvent

@esindger esindger added the Enhancement 🆕 New feature or request label Dec 13, 2018
@volodalexey
Copy link
Contributor Author

Nice to see fast support in this project! Thanks.

Actually, maybe I do not need "full" event object with users. What I need is "simple" reply() function.
Like in Telegraf reply().

  reply (...args) {
    this.assert(this.chat, 'reply')
    return this.telegram.sendMessage(this.chat.id, ...args)
  }

This function is used in a lot of examples:

bot.start((ctx) => ctx.reply('Welcome'))
bot.help((ctx) => ctx.reply('Send me a sticker'))
bot.on('sticker', (ctx) => ctx.reply('👍'))

The same I want to achieve with Airgram (however Airgram will be more powefull, so I can use it for bot and fo user). E.g. somewhere in updateNewMessage handler:

type OnlyOneMessageUpdateContext = /* here I want context that will contain only one message at time, so airgram will easily detect to which message it must reply */ UpdateContext;

airgram.updates.on(`updateNewMessage`, (ctx: OnlyOneMessageUpdateContext) => {
  if (update.message === '/start') {
    await ctx.reply('Hello!');
    await ctx.reply('Nice to meet you!'); // reply to the same message twice
  }
});
  1. Airgram should detect to whom airgram must reply (whether message was sent from chat or directly from user). I see that using bot API is much simpler in this case, just to use sendMessage and send chat or user id. With MTProto (Airgram) this will be harder task.
    Probably detect message type as
to_id: { _: 'peerChat', chat_id: ... } // then reply to chat
to_id: { _: 'peerUser', user_id: ... } // then reply to user
  1. Because of async handlers I should be confident that current context contains the same message (the same users array).

But anyway, if I will get access to users array in updateNewMessage I will try to implement reply() function on my own.

@esindger
Copy link
Collaborator

Is it possible to get access to "full" update event inside updateNewMessage handler?

Since v0.1.9 you have access to the parent update by ctx.parent property.

airgram.updates.on(`updateNewMessage`, (ctx: ag.UpdateContext) => {
  console.log(ctx.parent)
});

@esindger
Copy link
Collaborator

esindger commented Dec 14, 2018

For now, there is no plan to implement reply() function but we can refactor code to put creating of context into separate method createContext. Then you will be able to inherit this method and extend context.

@volodalexey
Copy link
Contributor Author

Since v0.1.9 you have access to the parent update by ctx.parent property.

Awesome! Thanks!

For now, there is no plan to implement reply() function but we can refactor code to put creating of context into separate method createContext. Then you will be able to inherit this method and extend context.

Got it. If you will make it - it would be nice.

@volodalexey
Copy link
Contributor Author

@esindger

airgram.updates.on(`updateNewMessage`, (ctx: ag.UpdateContext) => {
  console.log(ctx.parent)
});

In typescript I get compile error:

[ts] Property 'parent' does not exist on type 'UpdateContext<UpdatesResponse>'. [2339]

Am I missing something?

@esindger
Copy link
Collaborator

In typescript I get compile error:
[ts] Property 'parent' does not exist on type 'UpdateContext'. [2339]
Am I missing something?

Please check out package.lock which version is installed. This will work start from version 0.1.9.

@esindger
Copy link
Collaborator

Now you can extend updates context. Please check out the example

@volodalexey
Copy link
Contributor Author

Please check out package.lock which version is installed. This will work start from version 0.1.9.

Yep. With version 0.1.9 removed package-lock.json and run npm i - helped. Thanks!

Now you can extend updates context. Please check out the example

Awesome! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement 🆕 New feature or request question ❔ Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants