TelegramGateway
in package
Owns the Telegram side of the bridge: the update subscription, and a paced outbound queue.
There is nothing here corresponding to an IRC JOIN — Telegram pushes updates
for every chat the bot is a member of, whether or not the bridge is
interested — so membership is Telegram's business and filtering is
TelegramConnector's. What this class owns is pacing:
every outbound message passes a per-chat bucket and a global one, because
Telegram's limits are per-chat and per-bot at the same time and a burst that
respects only one of them still earns a 429.
TelegramPHP honours a 429's retry_after itself, so this is about not
earning one: a bot that keeps hitting the limit is throttled harder.
Tags
Table of Contents
Constants
- GLOBAL : mixed = 25
- And across every chat: about 30 a second.
- GLOBAL_SECONDS : mixed = 1.0
- MAX_QUEUE : mixed = 200
- How much may wait. A busy Discord channel can outrun a group's twenty a minute indefinitely, and a backlog that is still playing out an hour later is worse than a gap.
- PER_CHAT : mixed = 18
- Telegram's limit in a group: 20 messages a minute. Kept a little under.
- PER_CHAT_SECONDS : mixed = 60.0
Properties
- $clock : callable(): float|null
- $draining : bool
- $dropped : int
- How many messages were dropped since the backlog last cleared.
- $global : RateLimiter
- $limiters : array<string, RateLimiter>
- $logger : LoggerInterface
- $loop : LoopInterface
- $onEdit : callable(Message): void|null
- $onMessage : callable(Message): void|null
- $queue : array<int, Deferred}>
- $telegram : Telegram
Methods
- __construct() : mixed
- edit() : PromiseInterface<string|int, mixed>
- Rewrites a message the bot sent. Paced like a send, because Telegram counts it like one.
- listen() : void
- Starts listening.
- onEdit() : void
- Registers the handler for edits to messages already seen.
- onMessage() : void
- Registers the handler for inbound Telegram messages.
- queued() : int
- How many messages are waiting, for logging and health checks.
- send() : PromiseInterface<string|int, Message>
- Queues an HTML message for a Telegram chat.
- sendAnimation() : PromiseInterface<string|int, Message>
- Queues a GIF, by URL, as an animation.
- sendPhoto() : PromiseInterface<string|int, Message>
- Queues a photo, by URL — Telegram fetches it itself.
- dispatch() : void
- Sends one item and settles its promise, however the send fails.
- drain() : void
- Sends whatever the budgets allow, then re-arms a timer for the rest.
- enqueue() : PromiseInterface<string|int, mixed>
Constants
GLOBAL
And across every chat: about 30 a second.
public
mixed
GLOBAL
= 25
GLOBAL_SECONDS
public
mixed
GLOBAL_SECONDS
= 1.0
MAX_QUEUE
How much may wait. A busy Discord channel can outrun a group's twenty a minute indefinitely, and a backlog that is still playing out an hour later is worse than a gap.
public
mixed
MAX_QUEUE
= 200
PER_CHAT
Telegram's limit in a group: 20 messages a minute. Kept a little under.
public
mixed
PER_CHAT
= 18
Tags
PER_CHAT_SECONDS
public
mixed
PER_CHAT_SECONDS
= 60.0
Properties
$clock
private
callable(): float|null
$clock
$draining
private
bool
$draining
= false
$dropped
How many messages were dropped since the backlog last cleared.
private
int
$dropped
= 0
$global read-only
private
RateLimiter
$global
$limiters
private
array<string, RateLimiter>
$limiters
= []
Per-chat budget.
$logger read-only
private
LoggerInterface
$logger
$loop read-only
private
LoopInterface
$loop
$onEdit
private
callable(Message): void|null
$onEdit
= null
$onMessage
private
callable(Message): void|null
$onMessage
= null
$queue
private
array<int, Deferred}>
$queue
= []
$telegram read-only
private
Telegram
$telegram
Methods
__construct()
public
__construct(Telegram $telegram, LoopInterface $loop, LoggerInterface $logger[, callable(): float|null $clock = null ]) : mixed
Parameters
- $telegram : Telegram
- $loop : LoopInterface
- $logger : LoggerInterface
- $clock : callable(): float|null = null
-
For tests; defaults to the wall clock.
edit()
Rewrites a message the bot sent. Paced like a send, because Telegram counts it like one.
public
edit(int|string $chatId, int $messageId, string $html[, bool $caption = false ]) : PromiseInterface<string|int, mixed>
Parameters
- $chatId : int|string
- $messageId : int
- $html : string
- $caption : bool = false
-
Whether the message is a photo, whose text is its caption.
Return values
PromiseInterface<string|int, mixed>listen()
Starts listening.
public
listen() : void
Channel posts are relayed alongside group messages: to a reader in Discord the difference between someone talking in a group and a channel publishing a post is not interesting, and a bridge that silently ignored one of them would look broken.
A bot does not receive its own sends as updates, but the identity check is made anyway — two instances of this bridge pointed at one bot token would otherwise relay each other's output back and forth forever.
onEdit()
Registers the handler for edits to messages already seen.
public
onEdit(callable $handler) : void
Parameters
- $handler : callable
onMessage()
Registers the handler for inbound Telegram messages.
public
onMessage(callable $handler) : void
Parameters
- $handler : callable
queued()
How many messages are waiting, for logging and health checks.
public
queued() : int
Return values
intsend()
Queues an HTML message for a Telegram chat.
public
send(int|string $chatId, string $html[, array{reply_to?: int|string|null, silent?: bool} $options = [] ]) : PromiseInterface<string|int, Message>
Never sends around the budgets, even when they are full and the queue is empty: the ordering guarantee is what keeps a busy channel's messages arriving in the order they were typed.
Parameters
- $chatId : int|string
- $html : string
- $options : array{reply_to?: int|string|null, silent?: bool} = []
Return values
PromiseInterface<string|int, Message> —resolves when Telegram accepts it
sendAnimation()
Queues a GIF, by URL, as an animation.
public
sendAnimation(int|string $chatId, string $url[, string|null $caption = null ]) : PromiseInterface<string|int, Message>
Not through sendPhoto(): Telegram turns a GIF sent as a photo into a still of its first frame. Paced and captioned the same way.
Parameters
- $chatId : int|string
- $url : string
- $caption : string|null = null
Return values
PromiseInterface<string|int, Message>sendPhoto()
Queues a photo, by URL — Telegram fetches it itself.
public
sendPhoto(int|string $chatId, string $url[, string|null $caption = null ]) : PromiseInterface<string|int, Message>
Discord's CDN links are public for long enough for that, so handing Telegram the URL avoids pulling several megabytes through this process only to push them straight back out.
Parameters
- $chatId : int|string
- $url : string
- $caption : string|null = null
Return values
PromiseInterface<string|int, Message>dispatch()
Sends one item and settles its promise, however the send fails.
private
dispatch(Deferred} $item) : void
A send that throws before it has a promise — a bad argument, say — must still settle, or the caller waits forever.
Parameters
- $item : Deferred}
drain()
Sends whatever the budgets allow, then re-arms a timer for the rest.
private
drain() : void
A chat that is out of tokens is skipped rather than blocking the queue behind it, so one busy bridge cannot stall every other one. The global bucket is the exception: when that is empty nothing can go anywhere, so the loop stops immediately and keeps the remaining order intact.
enqueue()
private
enqueue(string $chatId, callable(): PromiseInterface $send) : PromiseInterface<string|int, mixed>
Parameters
- $chatId : string
- $send : callable(): PromiseInterface