State Management Example Bot
In this example section, we will create a bot that demonstrates Telegram's state management system. The bot will guide users through a multi-step conversation to collect their name and age, using states to maintain context between interactions.
We will use the following handlers:
onMessage
withfilter.commands()
for command triggersonMessage
withfilter.state()
for state-specific message handling
Import necessary classes
package io.github.natanimn;
import io.github.natanimn.telebof.BotClient;
import io.github.natanimn.telebof.BotContext;
import io.github.natanimn.telebof.enums.ParseMode;
import io.github.natanimn.telebof.types.updates.Message;
Create StateExampleBot
class and initialize BotClient
with state handlers
public class StateExampleBot {
BotClient bot;
public StateExampleBot(String token){
bot = new BotClient(token);
// Register handlers for different states and commands
bot.onMessage(filter -> filter.commands("start"), this::start);
bot.onMessage(filter -> filter.commands("cancel") && filter.state("*"), this::cancel);
bot.onMessage(filter -> filter.state("name") && filter.text(), this::getName);
bot.onMessage(filter -> filter.state("age") && filter.text(), this::getAge);
}
}
Our bot will manage the following conversation flow using states:
- /start command → Sets state to
"name"
and asks for user's name - User provides name → Sets state to
"age"
and asks for age - User provides age → Processes both pieces of information and clears state
- /cancel command → Clears current state at any point in the conversation
State Handlers Implementation
1. Start Handler - Initiating the Conversation
The /start
command begins the multi-step interaction by setting the initial state.
private void start(BotContext ctx, Message message){
// Ask for the user's name
ctx.sendMessage(message.from.id, "Hey! What is your name?").exec();
// Set the user's state to "name" to indicate we're expecting their name next
ctx.setState(message.from.id, "name");
}
Explanation:
setState(user_id, "name")
marks that this user is now in the "name" state- The next message from this user will be processed by the
getName
handler
2. Name Handler - Collecting the Name
This handler is triggered when a user in the "name"
state sends any message.
private void getName(BotContext ctx, Message message){
// Ask for the user's age
ctx.sendMessage(message.from.id, "How old are you?").exec();
// Transition to the "age" state
ctx.setState(message.from.id, "age");
// Store the provided name in state data for later use
var data = ctx.getStateData(message.from.id);
data.put("name", message.text);
}
Key Concepts:
filter.state("name")
ensures this handler only processes messages from users in the "name" statefilter.text()
ensures that user only entertext
getStateData(user_id)
retrieves a Map where we can store temporary conversation datadata.put("name", message.text)
saves the user's name for the final summary
3. Age Handler - Collecting and Processing Age
This handler processes messages from users in the "age"
state.
private void getAge(BotContext ctx, Message message){
int age;
// Validate that the input is a number
try {
age = Integer.parseInt(message.text);
} catch (NumberFormatException e) {
ctx.sendMessage(message.from.id, "Please enter a valid number").exec();
return; // Stay in the "age" state until valid input is provided
}
// Retrieve the stored name from state data
var data = ctx.getStateData(message.from.id);
// Send confirmation message
ctx.sendMessage(message.from.id, "Thank you for the information you have provided.").exec();
// Display the collected information
ctx.sendMessage(message.from.id,
String.format("<b>Name:</b> %s\n<b>Age:</b> %d", data.get("name"), age))
.parseMode(ParseMode.HTML)
.exec();
// The state is automatically cleared after the conversation completes
ctx.clearState(message.from.id);
}
Explanation:
- Input validation ensures we get a valid age before proceeding
data.get("name")
retrieves the name stored in the previous step- The state is automatically handled by the framework after completion
4. Cancel Handler - Aborting the Conversation
The /cancel
command can be used at any point to abort the current conversation.
private void cancel(BotContext ctx, Message message){
// Clear the user's current state and any stored data
ctx.clearState(message.from.id);
ctx.sendMessage(message.from.id,
"Your information has been cleared. Type /start to begin again.").exec();
}
Key Feature:
filter.state("*")
matches users in any active state, allowing cancellation from any stepclearState(user_id)
removes both the state marker and any associated data
Running the Bot
public void run(){
bot.startPolling();
}
public static void main(String[] args){
var token = System.getenv("TOKEN"); // Get token from environment variable
var state_bot = new StateExampleBot(token);
state_bot.run();
}
Conversation Flow Example
- User sends
/start
→ Bot sets state to"name"
and asks for name - User provides name → Bot stores name, sets state to
"age"
, asks for age - User provides age → Bot displays collected information
- (Optional) User can send
/cancel
at any time to abort the process
The full source code can be found on examples/state_bot