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

Call for comments on bot.myStatus #1872

Open
MKRhere opened this issue Sep 2, 2023 · 6 comments · May be fixed by #1873
Open

Call for comments on bot.myStatus #1872

MKRhere opened this issue Sep 2, 2023 · 6 comments · May be fixed by #1873

Comments

@MKRhere
Copy link
Member

MKRhere commented Sep 2, 2023

We're working on a feature that simplifies my_chat_member into a group of events:

  • bot.myStatus("joined", handler) will trigger when the bot is added to a group
  • bot.myStatus("left", handler) will trigger when the bot leaves a group by itself (leaveChat)
  • bot.myStatus("blocked", handler) will trigger when a user blocks the bot in private chat

and so on. All possible events:

  • joined
  • left
  • banned
  • restricted
  • promoted
  • demoted
  • blocked
  • unblocked

You can also listen for multiple events at once, like:

bot.myStatus(["blocked", "left", "banned"],	async ctx => {
	console.log(ctx.status.change); // the matched status change
	await removeChatIdFromDb(ctx.chat.id);
});

However, a problem arises when one my_chat_member update can cause two changes at once. For example, restricting a bot will also demote it from admin. In that case, you'll get the event you're looking for first. For example:

bot.myStatus('restricted', handler);
bot.myStatus('demoted', handler);

This will cause restricted to fire, but not demoted.

One idea I have here is when multiple events are expected on the same handler, fire all that apply for each update:

bot.myStatus(['restricted', 'demoted'], handler);

Here we can fire all that apply, so even when the bot is (which was previously promoted) restricted without demoting, handler will be called for both demoted and restricted events (even though the underlying update is only one).

Also consider the order here. Even though restricted is first in the array, the demoted event is fired first. If user intends on performing some actions based on these events, having a normalised order is useful.

Take for instance:

bot.myStatus(['promoted', 'joined'], ctx => {
	switch (ctx.status.change) {
		case 'joined': {
			ctx.chatSession.status = "member";
			return ctx.reply("Hello group!");
		}
		case 'promoted': {
			ctx.chatSession.status = "admin";
			return ctx.reply("Yay, good to be admin!");
		}
	}
});

In this case, if promoted was fired first, then joined, the resulting state of chatSession will be inconsistent. So we must have a normalised order of firing. This could also be accomplished (without us firing multiple events per update) in userland, using next():

bot.myStatus('joined', (ctx, next) => {
	// ...
	return next();
});

bot.myStatus('promoted', ctx => {
	// ...
	return next();
});

This pattern works without us calling the handler once per event, but puts the onus on the user to write events in the correct order.

Do you agree that all matching events on a myStatus handler must be fired per update?

👍🏻 Upvote for yes (fire an ordered list of all matching events)
👎🏻 Downvote for no (just fire once and let userland handle it)
💭 Reply in thread for other responses

@darvesh
Copy link

darvesh commented Sep 2, 2023

Is bot.myStatus a placeholder? What do you think about bot.userStatus?

@MKRhere
Copy link
Member Author

MKRhere commented Sep 2, 2023

@darvesh

bot.myStatus fires on the bot's own status change in chats - based on my_chat_member. (In Bot API terminology, "me", "my" refers to the bot). userStatus could be designed in a similar way.

@MKRhere MKRhere linked a pull request Sep 2, 2023 that will close this issue
@darvesh
Copy link

darvesh commented Sep 2, 2023

In that case, a generic implementation (userStatus) would be better, right? We can check if the user is bot itself inside the handler (or filter?)

@MKRhere
Copy link
Member Author

MKRhere commented Sep 2, 2023

@darvesh

Bot API gives us my_chat_member and chat_member updates. Those could be translated to myStatus and userStatus events in Telegraf. This feature is mainly motivated by usecases such as "remove user/chat from my db if they block/remove me". I don't see any case where you'd want to listen for both the bot's status and any user's status in the same handler.

@KnorpelSenf
Copy link
Collaborator

I really like the idea to add helpers for status changes. They're indeed pretty confusing because they can go from any state to any other, so we should definitely do something here.

However, I find it confusing to add event listeners in between the middleware. It used to be the way that all methods on the bot installed middleware, and bringing in some inconsistency here looks strange.

If you want to use the middleware system and integrate with it, then you are no longer able to fire several events. This means that the only remaining suggestion is to leave the things to userland and have them call next. This will also leave a lot of the confusion to the users, unfortunately.

So yeah, I don't really know how to move forward with this :(

@MKRhere
Copy link
Member Author

MKRhere commented Sep 2, 2023

@KnorpelSenf

bringing in some inconsistency here looks strange

This means that the only remaining suggestion is to leave the things to userland and have them call next.

I understand, your concern is valid. We could leave the correct ordering of events and calling next() to userland and document it. Therefore, do you have any other comments on the design of the new API, if it were to integrate normally with the middleware system as currently in #1873?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants