Last active
November 26, 2021 19:56
-
-
Save slavafomin/97fd4a7844ade540d27925b04493298c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Transformer } from 'grammy/out/core/client'; | |
| import { Cache } from './cache'; | |
| export function createCachingTransformer(options?: { | |
| cacheTtl?: number; | |
| }): Transformer { | |
| const { cacheTtl = 5 * 1000 } = (options || {}); | |
| type Response = Promise<any>; | |
| const cache = new Cache<Response>({ | |
| defaultTtl: cacheTtl, | |
| }); | |
| // Removing expired responses from the cache | |
| setInterval(() => cache.evictExpired(), cacheTtl); | |
| // Transformer function | |
| return async (prev, method, payload) => { | |
| if ( | |
| method === 'answerCallbackQuery' && | |
| 'callback_query_id' in payload | |
| ) { | |
| const queryId = payload.callback_query_id; | |
| const cacheKey = `${method}/${queryId}`; | |
| // Ignoring duplicate requests | |
| if (cache.has(cacheKey)) { | |
| console.debug('Repeating redundant request', { method, queryId }); | |
| return cache.get(cacheKey); | |
| } | |
| console.debug('Allowing request', { method, queryId }); | |
| const response = prev(method, payload); | |
| console.debug('Adding request to cache', { method, queryId }); | |
| // Saving pending response to resolve | |
| // duplicate requests later on | |
| cache.add({ key: cacheKey, value: response }); | |
| // Returning response back to the pipeline | |
| return response; | |
| } | |
| // Letting other requests to be processed as is | |
| return prev(method, payload); | |
| }; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| interface CacheOptions { | |
| defaultTtl?: number; | |
| } | |
| type CacheKey = string; | |
| interface CacheItem<ValueType> { | |
| value: ValueType; | |
| freshTill: number; | |
| } | |
| export class Cache<ValueType> { | |
| private cache = new Map< | |
| CacheKey, | |
| CacheItem<ValueType> | |
| >(); | |
| constructor(private readonly options: CacheOptions) { | |
| } | |
| public add(options: { | |
| key: CacheKey; | |
| value: ValueType; | |
| ttl?: number; | |
| }) { | |
| const { key, value } = options; | |
| const { defaultTtl } = this.options; | |
| this.cache.set(key, { | |
| value, | |
| freshTill: Date.now() + (options.ttl || defaultTtl) | |
| }); | |
| } | |
| public has(key: CacheKey) { | |
| return this.cache.has(key); | |
| } | |
| public get(key: CacheKey) { | |
| return this.cache.get(key)?.value; | |
| } | |
| public evictExpired() { | |
| const now = Date.now(); | |
| this.cache.forEach((item, key) => { | |
| if (item.freshTill < now) { | |
| this.cache.delete(key); | |
| console.debug(`Item evicted: ${key}`); | |
| } | |
| }); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const response1 = await context.answerCallbackQuery({ | |
| text: 'Hello!', | |
| }); | |
| const response2 = await context.answerCallbackQuery(); | |
| if (response1 !== response2) { | |
| throw new Error(`Response must be cached!`); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Including automatic callback query answering suggested by @wojpawlik, this would look like the following: