A bidirectional message bridge that synchronizes communication across Discord and Telegram (and in the future, platforms like Signal). It runs on standard python applications and is optimized for Heroku deployment.
Platform integrations are abstracted through BasePlatformAdapter to allow dropping in any new chat service easily. Messages conform to a UniversalMessage data standard, routed by the BridgeRouter and managed by the BridgeOrchestrator. A DeduplicationCache (Redis) prevents echo loops across platforms.
The easiest way to host this bridge is utilizing a Heroku Worker dyno.
heroku create
git push heroku mainThe deduplication cache requires Redis. Use the free/hobby tier:
heroku addons:create heroku-redis:ecoConfigure bot authentication tokens:
heroku config:set DISCORD_TOKEN="YOUR_DISCORD_BOT_TOKEN"
heroku config:set TELEGRAM_TOKEN="YOUR_TELEGRAM_BOT_TOKEN"Configure CHANNEL_PAIRS parameter:
The bridge routes dynamically based on a JSON configuration of pairs.
heroku config:set CHANNEL_PAIRS='{"pairs":[{"id":"pair_1","platforms":{"discord":"DISCORD_CHANNEL_ID","telegram":"TELEGRAM_CHAT_ID"}}]}'Notes on CHANNEL_PAIRS JSON structure:
- A bridge requires minimum two platforms in a pair to forward anything.
- Discord channel IDs are integers but must be supplied as string values.
- Telegram chat IDs (including groups) often start with
-100and must be supplied as string values.
Scale your worker dyno (this repo runs purely on a worker, NO web dyno is needed):
heroku ps:scale worker=1To monitor message bridging or diagnose errors:
heroku logs --tailAdding a platform like WhatsApp or Slack is done entirely natively without altering core components.
- Create Adapter: Create a new module e.g.
adapters/slack_adapter.py. - Inherit: Have your adapter inherit from
adapters.base.BasePlatformAdapter. - Implement Abstract Methods: Implement
connect(),disconnect(), andsend_message(). - Call
handle_incoming_message: Wrap incoming events into theUniversalMessagestruct and pass intoself.handle_incoming_message(uni_msg, source_channel_id, message_id). - Add to Config: Update
config.pyto read the API tokens needed. - Register: Add it to the orchestrator load cycle inside
bot.py.
An interface stub at adapters/signal_adapter.py is prepared for Signal integration.
To implement:
- Choose an API layer (e.g., self-host
bbernhard/signal-cli-rest-apivia Docker, or use CallMeBot). - Override methods in
signal_adapter.pyto execute REST API calls using Python'saiohttp. - Set
SIGNAL_ENABLED=truein Heroku Config Vars, supplyingSIGNAL_PHONE_NUMBERandSIGNAL_API_URL. - Uncomment the orchestrator loading code in
bot.py. - Add signal mapped channels inside your
CHANNEL_PAIRSConfig Var:{"signal": "GROUP_ID"}.