- Go 99.5%
- Shell 0.4%
- Dockerfile 0.1%
| cmd/mautrix-jmpchat | ||
| connector | ||
| docs | ||
| patched-xmpp | ||
| .gitignore | ||
| .mise.toml | ||
| AGENTS.md | ||
| build-go.sh | ||
| docker-run.sh | ||
| Dockerfile | ||
| example-config.yaml | ||
| go.mod | ||
| go.sum | ||
| MEMO.md | ||
| README.md | ||
| simple-config.yaml | ||
Minimal Mautrix-Go Bridge: Quickstart Template 🚀
Welcome! This project provides a minimal, bare-bones template for creating a Matrix bridge using the powerful mautrix-go library, specifically leveraging its modern bridgev2 framework.
What is a Matrix Bridge?
A Matrix bridge connects the decentralized, open Matrix communication network to other, often proprietary, chat networks (like WhatsApp, Telegram, Discord, etc.). It acts as a translator, allowing users on Matrix to communicate with users on the other network, and vice-versa.
Building a bridge involves a lot of standard setup: handling Matrix connections, managing user logins, storing data, processing configuration, etc. This template handles that common boilerplate for you, letting you jump straight into the interesting part: connecting to your specific target network.
⚙️ Project Structure
Here's a breakdown of the key files:
-
main.go:- The main entry point. Handles command-line flags, configuration, logging, and the bridge's start/stop lifecycle using
mxmain. - You usually won't need to modify this much initially.
- The main entry point. Handles command-line flags, configuration, logging, and the bridge's start/stop lifecycle using
-
connector/my_connector.go:- ⭐ This is the main implementation of the network side of the bridge! ⭐
- Contains the
MyConnectorstruct, which implements thebridgev2.NetworkConnectorinterface. - This file defines the bridge's core properties (
GetName,GetCapabilities), handles loading user sessions (LoadUserLogin), and initiates the login process (GetLoginFlows,CreateLogin). - It also contains the main logic for handling events from Matrix (
HandleMatrixMessage, etc. - though these might be delegated).
-
connector/login.go:- Contains the logic for specific login flows (e.g.,
SimpleLoginfor username/password). - Implements
bridgev2.LoginProcessinterfaces to handle steps like asking for user input (Start,SubmitUserInput) and finalizing login.
- Contains the logic for specific login flows (e.g.,
-
connector/network_client.go(Optional but Recommended):- This file typically holds the client logic for interacting with the remote network for a specific logged-in user.
- You'd create a struct (e.g.,
MyNetworkClient) that implementsbridgev2.NetworkClient. - Methods here would handle sending messages to the remote network, fetching user/room info, handling typing notifications, etc., based on Matrix events forwarded from
connector/my_connector.go. - The
LoadUserLoginmethod inconnector/my_connector.gowould instantiate this client.
🚀 Getting Started: Building Your Bridge
Follow these steps to get your basic bridge running:
-
Clone/Copy Template:
- Get a local copy of this template directory (e.g.,
git clone ...or download ZIP).
- Get a local copy of this template directory (e.g.,
-
Implement Your Connector (
connector/my_connector.go):- Open
connector/my_connector.go. This is where you'll spend most of your time. - Goal: Replace the placeholder logic with real code to interact with your target network.
- Start by filling in:
GetName(): Provide accurate details about your bridge and the network it connects to.GetCapabilities(): Define what features your bridge supports (e.g., message formatting, read receipts).GetLoginFlows()/CreateLogin(): Implement the actual login mechanism for your target network. The current example is just a placeholder!LoadUserLogin(): This is crucial. When a user logs in, this function should establish their persistent connection to the remote network.Start()/Stop(): Add any global setup/teardown logic for your network connection.
- Configuration: If your network needs API keys or other settings, implement
GetConfig()to load them from a file (likesimple-config.yaml) and create that YAML file.
- Open
-
Historic messages / chat history:
- This is called backfilling and happens in
network_client_backfill.go - When the user opens a room, this function will get called. Use this hook to backfill messages
- For this to get called, you need to set
backfillto true in config.yaml
- This is called backfilling and happens in
-
Generate Registration File:
- Open your terminal in the project directory.
- Run:
go run . -g -c config.yaml -r registration.yaml - This creates the initial
registration.yaml. Keep this file safe!
-
Configure the Bridge (
config.yaml):- Edit
config.yaml(generate it withgo run . --generate-example-config). - Set
homeserver.address(e.g.,https://matrix.example.com) andhomeserver.domain(e.g.,matrix.example.com). - Crucial: Copy the
id,as_token,hs_tokenfrom the generatedregistration.yamlinto theappservicesection ofconfig.yaml. Also, copybot.usernameand potentially adjustusername_template. - Review and adjust
database(default is./simple-bridge.db),logging, andpermissionsas needed. - If you created a network-specific config file (e.g.,
simple-config.yaml), configure its settings now.
- Edit
-
Configure Your Homeserver:
- Copy the generated
registration.yamlfile to your Matrix homeserver's configuration directory.- For Synapse, this is often
/etc/synapse/conf.d/or similar. Check your homeserver's documentation.
- For Synapse, this is often
- Restart your homeserver software (e.g.,
systemctl restart synapse). This makes it load the registration file and know about your bridge.
- Copy the generated
-
Build the Bridge:
- In the project directory, run:
go build - This creates an executable binary (e.g.,
minibridge).
- In the project directory, run:
-
Run the Bridge:
- Execute the binary, pointing it to your config files:
go run . -c config.yaml -r registration.yaml - Check the terminal output for logs and potential errors.
- Execute the binary, pointing it to your config files:
🧭 CLI Help & Config Generation
View available flags:
go run . --help
Generate an example config file at the path you pass to -c/--config:
go run . --generate-example-config -c config.yaml
🐳 Docker Builds
The Docker build uses a vendored module directory so patched dependencies (like XMPP auth) are included in the image.
🎉 Congratulations! You have a running (though perhaps very basic) Matrix bridge.
🧩 Common Bridge Patterns
1) How do I create rooms from remote rooms?
Use the portal + simplevent.ChatResync flow. When you discover a new remote chat, create or load the portal, store metadata, then queue a resync with CreatePortal = true. The framework will call GetChatInfo to build the room state and create the Matrix room. Suggested locations: connector/handle_remote.go (queue helper), connector/handle_matrix.go (GetChatInfo), and connector/types.go (portal metadata).
portalKey := networkid.PortalKey{ID: networkid.PortalID(remoteRoomID)}
portal, _ := bridge.GetPortalByKey(ctx, portalKey)
portal.OtherUserID = networkid.UserID(remoteUserID)
_ = portal.Update(ctx)
bridge.QueueRemoteEvent(login, &simplevent.ChatResync{
EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventChatResync,
PortalKey: portalKey,
CreatePortal: true,
},
ChatInfo: nil, // GetChatInfo will be called by the framework
})
2) How do I send a message into a Matrix room?
Queue a simplevent.Message (remote → Matrix). The framework converts and inserts it. See connector/handle_remote.go (QueueRemoteMessage).
nc.QueueRemoteMessage(ctx, msg.Portal.ID, "Hi there too")
3) How do I backfill messages?
Implement FetchMessages (BackfillingNetworkAPI). When backfill is enabled, the framework will call it and insert the returned messages. See connector/network_client_backfill.go.
func (nc *MyNetworkClient) FetchMessages(ctx context.Context, p bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) {
// build []*bridgev2.BackfillMessage and return
}
4) How do I react on a Matrix message?
Implement HandleMatrixMessage and take action for Matrix → remote, or queue a remote reply. See connector/handle_matrix.go.
func (nc *MyNetworkClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (*bridgev2.MatrixMessageResponse, error) {
nc.QueueRemoteMessage(ctx, msg.Portal.ID, "Hi there too")
return &bridgev2.MatrixMessageResponse{}, nil
}
⏭️ Next Steps
- Flesh out
connector/my_connector.go: Implement message handling, user/room synchronization, presence, typing notifications, etc. - Consult
mautrix-goDocs: Explore thebridgev2package documentation for detailed information on interfaces and helpers: pkg.go.dev/maunium.net/go/mautrix/bridgev2 - Study Other Bridges: Look at the source code of other
mautrix-gobased bridges (likemautrix-whatsapp,mautrix-telegram) for inspiration and examples. - Testing: Implement unit and integration tests for your connector logic.
- Refine Configuration: Make your bridge more robust by handling configuration validation and updates.
Good luck with your bridge development!