Session Plugin
Add persistent state to your bot with the Session Plugin.
The Session Plugin allows your bot to remember data across multiple updates. This is crucial for building complex interactions where you need to track user state, store temporary data like shopping cart items, or maintain user preferences.
Concept
Televerse sessions work by storing data associated with a specific chat (or user) and automatically loading it when a new update arrives. After your handlers finish processing the update, any changes to the session data are saved back to the storage.
Installation
The Session Plugin can be imported from the televerse/plugins/session library.
import 'package:televerse/plugins/session.dart';Basic Usage
To use sessions, you must extend the SessionContext class. This gives you access to the ctx.session property.
import 'package:televerse/televerse.dart';
import 'package:televerse/plugins/session.dart';
// 1. Define your custom context
class MyContext extends SessionContext<Map<String, dynamic>> {
MyContext(super.update, super.api, super.me);
}
void main() {
// 2. Create the bot with your custom context
final bot = Bot<MyContext>("TOKEN", contextConstructor: MyContext.new);
// 3. Initialize the session plugin
bot.plugin(SessionPlugin<MyContext, Map<String, dynamic>>(
initial: () => {'count': 0},
));
bot.command('count', (ctx) async {
// 4. Access session data
final session = ctx.session;
// Update data
session['count'] = (session['count'] as int) + 1;
await ctx.reply('Count: ${session['count']}');
});
bot.start();
}Type-Safe Sessions
For production apps, we recommend defining a class for your session data.
1. Define Session Data
class MySession {
int count;
String? username;
MySession({this.count = 0, this.username});
void increment() => count++;
}2. Define Custom Context
class MyContext extends SessionContext<MySession> {
MyContext(super.update, super.api, super.me);
}3. Setup and Usage
void main() {
final bot = Bot<MyContext>(
"TOKEN",
contextConstructor: MyContext.new,
);
bot.plugin(SessionPlugin<MyContext, MySession>(
initial: () => MySession(),
));
bot.command('count', (ctx) async {
// Type-safe access!
ctx.session.increment();
await ctx.reply('Count: ${ctx.session.count}');
});
bot.start();
}Storage Backends
By default, SessionPlugin uses MemorySessionStorage. This is fast and great for testing, but data is lost when the bot restarts.
For production, you should use a persistent storage backend (like File, Database, Redis, etc.). You can implement the SessionStorage interface to create your own backend.
class FileSessionStorage<T> implements SessionStorage<T> {
final File file;
// Implementation details...
Future<void> set(String key, T value) async {
// Write to file
}
Future<T?> get(String key) async {
// Read from file
}
// ... implement remove, has, clear
}Then use it in your plugin setup:
bot.plugin(SessionPlugin<MyContext, MySession>(
initial: () => MySession(),
storage: FileSessionStorage(File('./sessions.json')),
));Session Keys
By default, sessions are stored per chat. This means all users in a group share the same session, and a private chat has its own session.
You can change this behavior by providing a custom getSessionKey function. For example, to store sessions per user (regardless of which chat they are in):
bot.plugin(SessionPlugin<MyContext, MySession>(
initial: () => MySession(),
// Use user ID as part of the key
getSessionKey: (ctx) => 'user_${ctx.from?.id}',
));Important
Always ensure your getSessionKey handles cases where ctx.from or ctx.chat might be null (e.g., in certain updates). Return a fallback key or handle appropriately.