Skip to content

Instantly share code, notes, and snippets.

@waptik
Created April 2, 2021 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save waptik/ae5926418222a7d8687720b72353699a to your computer and use it in GitHub Desktop.
Save waptik/ae5926418222a7d8687720b72353699a to your computer and use it in GitHub Desktop.
implementation of telegraf-session using Prisma as datastore based on https://github.com/alexnzarov/telegraf-session-mongodb
import { Context, Telegraf } from 'telegraf'
import { PrismaClient } from '@prisma/client'
import { session } from 'utils/telegraf-session-prisma' // path to session module
const prisma = new PrismaClient()
interface SessionData {
messageCount: number
// ... more session data go here
}
// Define your own context type
interface MyContext extends Context {
session?: SessionData
// ... more props go here
}
if (process.env.BOT_TOKEN === undefined) {
throw new TypeError('BOT_TOKEN must be provided!')
}
// Create your bot and tell it about your context type
const bot = new Telegraf<MyContext>(process.env.BOT_TOKEN)
// Make session data available
bot.use(session(prisma))
// Register middleware
bot.on('message', async (ctx) => {
// set a default value
ctx.session ??= { messageCount: 0 }
ctx.session.messageCount++
await ctx.reply(`Seen ${ctx.session.messageCount} messages.`)
})
// Launch bot
// eslint-disable-next-line @typescript-eslint/no-floating-promises
bot.launch()
// Enable graceful stop
process.once('SIGINT', () => bot.stop('SIGINT'))
process.once('SIGTERM', () => bot.stop('SIGTERM'))
Terms
import { Context } from "telegraf"
export type SessionKeyFunction = (ctx: Context) => string | null
// Mocking the behaviour from the default memory session implementation.
// Source: https://telegraf.js.org/modules.html#session
// This is possible due to getters that fetch 'from' and 'chat' values from different sources.
export const getSessionKey = ({ from, chat }: Context) => {
if (from == null || chat == null) {
return null
}
return `${from.id}:${chat.id}`
}
# above are previous models
model Session {
id String @unique @default(uuid())
key String @unique
data Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
/**
* Telegraf session using Prisma as datastore
* @author gh:waptik
**/
import { Context, MiddlewareFn } from "telegraf"
import { getSessionKey, SessionKeyFunction } from "./keys"
import { PrismaClient } from "@prisma/client"
export type SessionOptions = {
sessionName: string
sessionKeyFn: SessionKeyFunction
}
export const session = <C extends Context = Context>(
db: PrismaClient,
sessionOptions?: Partial<SessionOptions>
): MiddlewareFn<C> => {
const options: SessionOptions = {
sessionName: "session",
sessionKeyFn: getSessionKey,
...sessionOptions,
}
const model = db[options.sessionName]
const saveSession = async (key: string, data: any) =>
await model.upsert({
where: {
key,
},
update: { data },
create: { key, data },
})
const getSession = async (key: string) => {
const res = await model.findUnique({ where: { key } })
return res?.data
}
const { sessionKeyFn: getKey, sessionName } = options
return async (ctx: Context, next) => {
const key = getKey(ctx)
const data = key == null ? undefined : await getSession(key)
ctx[sessionName] = data
await next()
if (ctx[sessionName] != null && key !== null) {
await saveSession(key, ctx[sessionName])
}
}
}
@waptik
Copy link
Author

waptik commented Apr 2, 2021

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