async-matrix
Async-native Matrix Application Service SDK for Ruby. Built on the Socketry ecosystem (async, async-http, Falcon). No threads, no callbacks -- just fibers.
Usage
Please see the project documentation for more details.
- Matrix Events Reference - Auto-generated documentation for every Matrix event type.
Install
gem "async-matrix"
Quick Start
# config.ru
require "async/matrix"
config = Async::Matrix::ApplicationService::Config.load("config/appservice.yml")
client = Async::Matrix::Client.new(config)
bot = Async::Matrix::ApplicationService::Bot.new(client) do
on "m.room.member" do |event|
join_room(event.room_id) if event.content.membership == "invite"
end
on "m.room.message", msgtype: "m.text", not_from: :self do |event|
send_notice event.room_id, "Echo: #{event.content.body}"
end
end
server = Async::Matrix::ApplicationService::Server.new(hs_token: config.appservice.hs_token)
server.register(bot)
run server
falcon serve --bind http://0.0.0.0:9292
A complete working example with Docker Compose and Synapse lives in examples/echo_bot/.
Handlers
Any object that responds to #event_types and #call(event) is a handler. Use this when you need more control than the Bot DSL provides.
class Echo
def initialize(client) = @client = client
def event_types = ["m.room.message"]
def call(event)
return unless event.content&.msgtype == "m.text"
return unless event.sender != @client.config.bot_mxid
@client.send_notice(event.room_id, "Echo: #{event.content.body}")
end
end
server.register(Echo.new(client))
Dispatch is fault-tolerant -- one handler raising won't take down the rest.
Client
client.send_text(room_id, "Hello world")
client.send_html(room_id, "<b>bold</b>")
client.send_notice(room_id, "Bot says hi")
client.join_room(room_id)
client.leave_room(room_id)
client.set_display_name("My Bot")
client.whoami
For anything beyond the convenience methods, client.api provides method-chained access to the full Matrix Client-Server API, validated at runtime against the official OpenAPI specs:
client.api.createRoom.post(name: "Pub")
client.api.rooms("!room:ex.com")..get(dir: "b", limit: 10)
All methods are fiber-safe with automatic connection pooling.
Configuration
Create config/appservice.yml for your bot:
homeserver:
address: "http://synapse:8008"
domain: "localhost"
appservice:
as_token: "your-appservice-token"
hs_token: "your-homeserver-token"
bot:
username: "bot"
You'll also need a registration.yml registered with your homeserver. See the echo bot example for a working template.
Override the config path at runtime:
APPSERVICE_CONFIG=/etc/bot/appservice.yml falcon serve
Built With
- async -- fiber-based concurrency framework
- async-http -- HTTP client/server with connection pooling
- falcon -- async Rack-compatible web server
- json_schemer -- JSON Schema validation
- scampi -- inline co-located test framework
- string_builder -- method-chain string builder
License
Apache 2.0