It is not very clear how to work with data from external storage to initialize the initial data of the user's session.
For example, when working with Redis adapter and lazySession
:
import { Bot, Context, LazySessionFlavor, Enhance, lazySession, enhanceStorage } from 'grammy'
import { RedisAdapter } from '@grammyjs/storage-redis'
import { Redis } from 'ioredis'
// ...
interface IUserSessionData {
counter: number
}
type TUserContext = Context & LazySessionFlavor<IUserSessionData>
const bot = new Bot<TUserContext>(process.env.TELEGRAM_BOT_TOKEN)
const redis = new Redis({
host: process.env.REDIS_HOST,
password: process.env.REDIS_PASSWORD,
username: process.env.REDIS_USERNAME ? process.env.REDIS_USERNAME : 'default',
port: process.env.REDIS_PORT ? Number(process.env.REDIS_PORT) : 6379,
lazyConnect: true,
})
const enhanced = new RedisAdapter<Enhance<IUserSessionData>>({ instance: redis })
const storage = enhanceStorage({
storage: enhanced,
millisecondsToLive: 30 * 60 * 1000,
})
bot.use(
lazySession({
initial: () => ({ /* ??? */ }),
getSessionKey: (ctx: Omit<TUserContext, 'session'>) => ctx.from?.id.toString(),
storage,
}),
)
// ...
What do I need to do so that when creating middleware with session settings, I can pick up the current data? Now, every time the bot is rebooted, the session is reset to those specified in initial
block in lazySession
.
Since the session key in Redis is equal to the user ID in Telegram (according to the snippet above), in order to programmatically insert all data from Redis into the ctx.session
, I need to make a separate function, which should be at the beginning of each bot.*(...)
, etc.?
How would I improve this?
It would be convenient if the session initialization method could retrieve data from the remote storage itself.
And if there is no data (or the storage is unavailable), then take the specified fallback values.
Or let the developer configure the function himself, which will take data from Redis and put it in the ctx.session
of the current bot user:
bot.use(
lazySession({
initial: () => ({ counter: 0 }), // <-- fallback values here
getInitialSessionData: (ctx) => myFunc(ctx), // <-- send context with current Telegram user ID to get Redis record by key
getSessionKey: (ctx: Omit<TUserContext, 'session'>) => ctx.from?.id.toString(),
storage,
}),
)
I think, such an improvement would be useful for everyone (especially for beginners) and would make the bot code much easier.