mautrix-go

repository·main·Indexed 20 days ago

https://github.com/mautrix/go

A comprehensive Golang framework for interacting with the Matrix protocol. It extends the gomatrix client with advanced features including Appservice support, E2EE, partial federation, and a media proxy. It includes Megabridge (bridgev2), a high-level framework for building puppeting Matrix bridges using a modular architecture of network connectors, a central bridge module, and Matrix connectors.

Tokens
13.9K
Snippets
47
Records
76
Agent score
68%

What's inside mautrix-go

  1. What is Megabridge (bridgev2)?

    main
    Megabridge (also known as bridgev2) is a high-level framework designed for writing puppeting Matrix bridges with minimal boilerplate. It abstracts the complexities of bridging by separating the logic into three distinct components: network connectors, a central bridge module, and Matrix connectors.
  2. Overview of mautrix-go Matrix framework

    main

    mautrix-go is a Golang framework for building Matrix-related applications. It is a fork/extension of matrix-org/gomatrix and provides advanced features beyond a basic client API. It is used by several major projects including gomuks, go-neb, and mautrix-whatsapp.

    Key capabilities include:

    • Appservice Support: Implementation of the Intent API and room state storage.
    • End-to-End Encryption (E2EE): Support for key backup, cross-signing, and interactive verification.
    • Puppeting Bridges: A high-level module specifically designed for building bridges that puppet user accounts.
    • Partial Federation: Modules for making federation requests, processing PDUs (Persistent Data Units), and event authorization.
    • Media Proxy: A server capable of exposing arbitrary content as a Matrix media repository.
    • Synapse Integration: Wrapper functions for the Synapse admin API.
    • Matrix Utilities: Structs for parsing event content, helpers for Matrix HTML generation/parsing, and helpers for handling push rules.
  3. How Megabridge architecture works

    main

    Megabridge follows a modular architecture consisting of three main parts:

    1. Network Connectors: Handle the protocol-specific details of the remote (non-Matrix) network.
    2. Central Bridge Module: Contains the core generic bridge logic, including message handling and portal mapping.
    3. Matrix Connectors: Handle the connection to Matrix. Supported implementations include standard Application Services and Beeper's local bridge system.

    The central bridge module interacts with these components via defined interfaces. Connectors are also permitted to call interface methods on the opposite side directly.

  4. How the login process works

    main

    Logins in Megabridge are managed as state machines using LoginProcess. The process involves three types of steps:

    • user_input: Requests information from the user (e.g., phone number, username, password, 2FA code).
    • cookies: Requests browser cookies, either via manual extraction or an automated webview.
    • display_and_wait: Displays data (like a QR code) and waits for the remote network to authorize the login.

    Standard Login Flow

    1. The login handler calls NetworkConnector.GetLoginFlows to retrieve available flows.
    2. The handler calls NetworkConnector.CreateLogin with a chosen flow ID, which returns a LoginProcess object.
    3. The handler calls LoginProcess.Start to receive the initial step.
    4. The handler iterates through steps by calling Wait, SubmitUserInput, or SubmitCookies as required by the step data.
    5. Once finished, the LoginProcess creates a UserLogin object and returns a complete step.
  5. How to implement a new network connector

    main

    To create a new network connector in Megabridge, you must implement the following four interfaces:

    • NetworkConnector: The main entry point for the remote network. It handles non-user-specific tasks, creates NetworkAPI instances, and initiates login flows.
    • LoginProcess: A state machine that manages the lifecycle of logging into the remote network.
    • NetworkAPI: The client instance for a single logged-in user. It maintains the connection, receives/sends events, and fetches metadata (chat/user info).
    • RemoteEvent: Represents a single event from the remote network (e.g., a message or reaction). When a NetworkAPI receives an event, it must wrap it in a RemoteEvent and pass it to the bridge using Bridge.QueueRemoteEvent.
  6. Handle unknown commands

    main

    The processor supports a fallback mechanism for commands that do not match any registered handler.

    • The constant UnknownCommandName is defined as "__unknown-command__".
    • You can register a specific handler for unknown commands using MakeUnknownCommandHandler[MetaType](prefix) during initialization.
    • If a command is sent that matches the prefix but no handler (including the unknown handler) is found, the command is silently ignored.
  7. How command state and multi-step commands work

    main

    The Processor supports stateful commands where a single command might require multiple inputs from the user.

    1. State Storage: Command state is stored on the bridgev2.User object using atomic pointers (LoadCommandState, StoreCommandState, SwapCommandState).
    2. Stateful Flow: When a message arrives, the Processor checks if the user has an active CommandState. If state.Next is present, the incoming message is treated as a reply to the ongoing command rather than a new command. The state.Next.Run(ce) method is then called to continue the sequence.
    3. Cancellation: Users can break out of this state by issuing the cancel command, which clears the state and executes any cleanup logic defined in the state's Cancel field.
  8. Combine multiple PreValidators with AllPreValidator and AnyPreValidator

    main

    You can compose multiple validation rules using logical combinators:

    • AllPreValidator: A slice of validators that acts like a logical AND. The event is only processed if all validators return true.
    • AnyPreValidator: A slice of validators that acts like a logical OR. The event is processed if at least one validator returns true.
  9. Create nested subcommands

    main

    The Handler struct supports hierarchical command structures via the Subcommands field. You can nest Handler instances within each other to create complex command trees.

    When a command has subcommands, the system uses an internal CommandContainer to manage and register them. To ensure the hierarchy is correctly initialized, the initSubcommandContainer() method must be called (typically handled by the framework's registration process).

  10. Redact a command with Redact()

    main

    Use Redact(req ...mautrix.ReqRedact) to redact the original command event in the room. This is typically used for security or cleanup after a command has been processed.

    Note: This method does not return a value and logs errors internally if the redaction fails.

    ce.Redact()
  11. Manage User Profiles and Account Data

    main

    You can manage user profile information and account-level data using the following methods:

    Profile Management

    • SetDisplayName(ctx, displayName): Sets the user's display name.
    • GetDisplayName(ctx, mxid): Retrieves the display name for a specific user.
    • SetAvatarURL(ctx, url): Sets the user's avatar URL.
    • GetAvatarURL(ctx, mxid): Gets the avatar URL for a specific user.
    • SetProfileField(ctx, key, value): Sets an arbitrary profile field. Note that for non-standard fields, the client may use an unstable MSC endpoint if the server doesn't support arbitrary profile fields.
    • DeleteProfileField(ctx, key): Deletes an arbitrary profile field.
    • GetProfileField(ctx, userID, key, into): Retrieves a specific profile field and unmarshals it into the into pointer.

    Account Data

    • SetAccountData(ctx, name, data): Sets account data of a specific type for the current user.
    • GetAccountData(ctx, name, output): Retrieves account data of a specific type.
    • SetRoomAccountData(ctx, roomID, name, data): Sets account data specific to a room.
    • GetRoomAccountData(ctx, roomID, name, output): Retrieves room-specific account data.
  12. Handle Matrix reaction commands

    main

    The ParseReaction function allows a processor to intercept Matrix reaction events that are intended to trigger specific commands.

    How it works

    1. Detection: It checks if a reaction event relates to a target event via a key that starts with the configured proc.ReactionCommandPrefix.
    2. Validation: It ensures the target event was sent by the bot itself and is not redacted.
    3. Decryption: If the target event is encrypted, it uses the client's crypto helper to decrypt it.
    4. Command Extraction: It looks for command data stored in the target event's raw content under the key fi.mau.reaction_commands.
    5. Command Types:
      • String commands: Handled via RawTextToEvent.
      • Structured commands: Handled via StructuredCommandToEvent using event.MSC4391BotCommandInput format.
    6. Cleanup: If the target event does not have the fi.mau.reaction_multi_use key set to true, the function calls DeleteAllReactions to remove all reactions from the target event after processing.

    Data Keys

    • fi.mau.reaction_commands: A map in the target event's raw content where keys are reaction keys and values are the command data.
    • fi.mau.reaction_multi_use: A boolean in the target event's raw content determining if reactions should be preserved.
    func (proc *Processor[MetaType]) ParseReaction(ctx context.Context, evt *event.Event) *Event[MetaType]