Bridge from jmp.chat <-> matrix
  • Go 99.5%
  • Shell 0.4%
  • Dockerfile 0.1%
Find a file
2026-03-30 18:28:19 -07:00
cmd/mautrix-jmpchat Fix build: un-ignore cmd and use go 1.24 2026-02-27 11:22:56 -08:00
connector support blocking 2026-03-30 18:28:19 -07:00
docs jmpchat bridge login fix 2026-02-28 18:58:20 -08:00
patched-xmpp conform to cheogram 2026-03-23 22:50:34 -07:00
.gitignore ignore 2026-03-01 05:14:07 -08:00
.mise.toml Update matrix deps and Go toolchain 2025-12-27 11:35:35 +07:00
AGENTS.md bridge init 2026-02-26 14:30:55 -08:00
build-go.sh jmpchat bridge login fix 2026-02-28 18:58:20 -08:00
docker-run.sh docker 2026-02-26 17:28:24 -08:00
Dockerfile jmpchat bridge login fix 2026-02-28 18:58:20 -08:00
example-config.yaml Modernize bridge layout to match other bridges 2025-12-27 14:05:57 +07:00
go.mod jmpchat bridge login fix 2026-02-28 18:58:20 -08:00
go.sum jmpchat bridge login fix 2026-02-28 18:58:20 -08:00
MEMO.md Add simple reply on message, register portals 2025-04-04 11:31:44 +09:00
README.md jmpchat bridge login fix 2026-02-28 18:58:20 -08:00
simple-config.yaml bridge init 2026-02-26 13:54:00 -08:00

Minimal Mautrix-Go Bridge: Quickstart Template 🚀

Go Reference

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.
  • connector/my_connector.go:

    • This is the main implementation of the network side of the bridge!
    • Contains the MyConnector struct, which implements the bridgev2.NetworkConnector interface.
    • 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., SimpleLogin for username/password).
    • Implements bridgev2.LoginProcess interfaces to handle steps like asking for user input (Start, SubmitUserInput) and finalizing login.
  • 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 implements bridgev2.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 LoadUserLogin method in connector/my_connector.go would instantiate this client.

🚀 Getting Started: Building Your Bridge

Follow these steps to get your basic bridge running:

  1. Clone/Copy Template:

    • Get a local copy of this template directory (e.g., git clone ... or download ZIP).
  2. 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 (like simple-config.yaml) and create that YAML file.
  3. 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 backfill to true in config.yaml
  4. 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!
  5. Configure the Bridge (config.yaml):

    • Edit config.yaml (generate it with go run . --generate-example-config).
    • Set homeserver.address (e.g., https://matrix.example.com) and homeserver.domain (e.g., matrix.example.com).
    • Crucial: Copy the id, as_token, hs_token from the generated registration.yaml into the appservice section of config.yaml. Also, copy bot.username and potentially adjust username_template.
    • Review and adjust database (default is ./simple-bridge.db), logging, and permissions as needed.
    • If you created a network-specific config file (e.g., simple-config.yaml), configure its settings now.
  6. Configure Your Homeserver:

    • Copy the generated registration.yaml file to your Matrix homeserver's configuration directory.
      • For Synapse, this is often /etc/synapse/conf.d/ or similar. Check your homeserver's documentation.
    • Restart your homeserver software (e.g., systemctl restart synapse). This makes it load the registration file and know about your bridge.
  7. Build the Bridge:

    • In the project directory, run: go build
    • This creates an executable binary (e.g., minibridge).
  8. 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.

🧭 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-go Docs: Explore the bridgev2 package 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-go based bridges (like mautrix-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!