Class: Async::Matrix::ApplicationService::Server

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/async/matrix/application_service/server.rb

Overview

Matrix Application Service (server side).

A Server wraps a Grape::API into which the Matrix wire-protocol routes are mixed (via the Grape concern). It forwards the Grape route DSL, so you can declare application-specific endpoints right alongside the Matrix routes, and register event handlers with #dispatch:

server = Async::Matrix::ApplicationService::Server.new(
hs_token: config.appservice.hs_token,
client:   Async::Matrix::Client.new(config)
) do
dispatch do
  on "m.room.member" do |event|
    join_room(event.room_id) if event.content.membership == "invite"
  end
end

dispatch SomeHandler.new       # plain handler or Bot

post "/_webhook/send" do       # your own endpoint, no Matrix auth
  client.send_text(params[:room_id], params[:body])
  {ok: true}
end
end

run server

Server is a Rack app (it delegates #call to the wrapped Grape::API), so run server works directly, and it can be mounted into a larger Rack app.

Grape is a plain mix-in, so you can also skip Server entirely and mix the routes straight into your own Grape::API:

class MyAppService < Grape::API
include Async::Matrix::ApplicationService::Server::Grape
post("/_webhook/send") { ... }
end
MyAppService.configure { |c| c[:hs_token] = ...; c[:dispatcher] = ... }

Defined Under Namespace

Modules: Grape

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hs_token:, dispatcher: Dispatcher.new, client: nil, thirdparty: nil, &block) ⇒ Server

Returns a new instance of Server.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/async/matrix/application_service/server.rb', line 217

def initialize(hs_token:, dispatcher: Dispatcher.new, client: nil, thirdparty: nil, &block)
  @dispatcher = dispatcher
  @client     = client

  # A fresh Grape::API with the Matrix routes mixed in, configured with
  # our collaborators. No mounting — the routes are defined inline by the
  # concern, so adding app-specific routes never triggers a re-mount.
  @api = ::Class.new(::Grape::API)
  @api.include(Grape)
  @api.configure do |c|
    c[:hs_token]   = hs_token
    c[:dispatcher] = dispatcher
    c[:thirdparty] = thirdparty
    c[:client]     = client
  end

  instance_eval(&block) if block
end

Instance Attribute Details

#apiObject (readonly)

Returns the value of attribute api.



215
216
217
# File 'lib/async/matrix/application_service/server.rb', line 215

def api
  @api
end

#clientObject (readonly)

Returns the value of attribute client.



215
216
217
# File 'lib/async/matrix/application_service/server.rb', line 215

def client
  @client
end

#dispatcherObject (readonly)

Returns the value of attribute dispatcher.



215
216
217
# File 'lib/async/matrix/application_service/server.rb', line 215

def dispatcher
  @dispatcher
end

Instance Method Details

#dispatch(handler = nil, &block) ⇒ Object

Register handlers with the dispatcher. Sugar over dispatcher.register:

dispatch do                          # block → Bot built with `client`
on "m.room.message" do |e| ... end
end
dispatch Bot.new(other_client) { }   # explicit bot
dispatch SomeHandler.new             # plain handler


244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/async/matrix/application_service/server.rb', line 244

def dispatch(handler = nil, &block)
  if block
    unless @client
      raise ArgumentError, "dispatch { ... } needs a client; pass `client:` to Server.new"
    end

    @dispatcher.register(Bot.new(@client, &block))
  elsif handler
    @dispatcher.register(handler)
  else
    raise ArgumentError, "dispatch requires a handler argument or a block"
  end
  @dispatcher
end