Getting Started

This guide installs async-matrix and makes authenticated calls against a Matrix homeserver from inside an async reactor.

If what you want is the server side — a service your homeserver PUTs transactions at, dispatching events to handlers — that is async-matrix-bridge, which depends on this gem. Everything below still applies: the bridge hands you the same Client.

Requirements

  • Ruby >= 3.3
  • A Matrix homeserver and an access token for it

async-matrix ships a native Rust extension for end-to-end encryption. gem install serves a precompiled gem for common platforms; on anything else it compiles at install time and needs a Rust toolchain.

Installation

# Gemfile
gem "async-matrix"
bundle install

Configuration

A Config is a YAML file (or plain hash) exposed through dot notation. Client reads exactly two fields from it — homeserver.address and appservice.as_token — and ignores the rest:

# config/appservice.yml
homeserver:
  address: "http://synapse:8008"
  domain: "localhost"

appservice:
  as_token: "long-random-string-A"
  bot:
    username: "bot"
require "async/matrix"

config = Async::Matrix::Config.load("config/appservice.yml")

config.homeserver.address   # => "http://synapse:8008"
config.bot_mxid             # => "@bot:localhost"

Config validates nothing — it vivifies whatever you hand it. A subclass adds validation by overriding .validate!, which is how async-matrix-bridge layers the mautrix bridgev2 JSON Schema suite on top without reimplementing the loading.

Building one inline works too, which is handy in specs:

config = Async::Matrix::Config.new(
  "homeserver" => {"address" => "http://localhost:8008", "domain" => "localhost"},
  "appservice" => {"as_token" => "token", "bot" => {"username" => "bot"}}
)

Making calls

Every Client method is a fiber operation, so calls belong inside an async reactor:

client = Async::Matrix::Client.new(config)

Async do
  client.join_room("!room:example.org")
  client.send_text("!room:example.org", "Hello world")
  client.send_notice("!room:example.org", "A notice")
  client.send_html("!room:example.org", "<b>bold</b>")
end

Concurrency is what fibers buy you — these run in parallel over a pooled connection, not one after another:

Async do
  rooms.map { |id| Async { client.send_notice(id, "broadcast") } }.each(&:wait)
end

The client retries 502/503/504 with exponential backoff and full jitter, honours Retry-After on 429, and caps response bodies while streaming them. See the Client page for the per-request knobs and the full method list.

Beyond the convenience methods

The convenience methods cover the common cases. For anything else, client.api builds a path by method chaining and validates it against the official Matrix Client-Server OpenAPI documents bundled in the gem:

Async do
  client.api.account.whoami.get
  client.api.createRoom.post(name: "Pub", preset: "public_chat")
  client.api.rooms("!room:example.org").messages.get(dir: "b", limit: 10)
end

Binary routes (upload, download, thumbnail) are detected and dispatched to the media client automatically.

Events

Events parse into Async::Matrix::Event, with dot-accessible content and optional validation against the upstream Matrix event schemas:

event = Async::Matrix::Schema.parse(raw_hash)

event.type              # => "m.room.message"
event.sender            # => "@alice:example.org"
event.content.body      # => "hello"
event.valid?            # => true
event.valid!            # => true, or raises Schema::ValidationError

Next: the Client in full, or events and schema validation.


This site uses Just the Docs, a documentation theme for Jekyll.