Class: ActiveMatrix::Bot::Base
- Inherits:
-
Object
- Object
- ActiveMatrix::Bot::Base
- Extended by:
- Extensions
- Includes:
- Logging
- Defined in:
- lib/active_matrix/bot/base.rb
Direct Known Subclasses
Defined Under Namespace
Classes: RequestHandler
Constant Summary collapse
- CALLERS_TO_IGNORE =
[ /\/matrix_sdk\/.+\.rb$/, # all ActiveMatrix code /^\(.*\)$/, # generated code /rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks /bundler(\/(?:runtime|inline))?\.rb/, # bundler require hacks /<internal:/ # internal in ruby >= 1.9.2 ].freeze
- EMPTY_BOT_FILTER =
A filter that should only result in a valid sync token and no other data
{ account_data: { types: [] }, event_fields: [], presence: { types: [] }, room: { account_data: { types: [] }, ephemeral: { types: [] }, state: { types: [], lazy_load_members: true }, timeline: { types: [] } } }.freeze
Class Attribute Summary collapse
-
.handlers ⇒ Object
readonly
Returns the value of attribute handlers.
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
-
#event ⇒ Object
readonly
Returns the value of attribute event.
- #logger ⇒ Object
Class Method Summary collapse
-
.all_handlers(type: :command) ⇒ Array[RequestHandler]
Retrieves all registered - including inherited - handlers for the bot.
-
.client(&block) ⇒ Object
Registers a block to be run when configuring the client, before starting the sync.
-
.command(command, desc: nil, notes: nil, only: nil, **params) ⇒ Object
Register a bot command.
-
.command?(command, ignore_inherited: false) ⇒ Boolean
Check if a command is registered.
-
.disable(*opts) ⇒ Object
Same as calling ‘set :option, false` for each of the given options.
-
.enable(*opts) ⇒ Object
Same as calling ‘set :option, true` for each of the given options.
-
.event(event, only: nil, **_params) ⇒ Object
Register a Matrix event.
-
.event?(event, ignore_inherited: false) ⇒ Boolean
Check if an event is registered.
-
.get_command(command, ignore_inherited: false) ⇒ RequestHandler?
Retrieves the RequestHandler for a given command.
-
.get_event(event, ignore_inherited: false) ⇒ RequestHandler?
Retrieves the RequestHandler for a given event.
- .logger ⇒ Object
-
.quit! ⇒ Object
Stops any running instance of the bot.
-
.remove_command(command) ⇒ Object
Removes a registered command from the bot.
-
.remove_event(event) ⇒ Object
Removes a registered event from the bot.
-
.reset! ⇒ Object
Reset the bot class, removing any local handlers that have been registered.
-
.run!(options = {}) ⇒ Object
Starts the bot up.
-
.running? ⇒ Boolean
Check whether the self-hosted server is running or not.
-
.set(option, value = (not_set = true), ignore_setter = false, &block) ⇒ Object
Set a class-wide option for the bot.
-
.settings ⇒ Object
Access settings defined with Base.set.
Instance Method Summary collapse
- #bot ⇒ Object
-
#command?(command, **params) ⇒ Boolean
Checks for the existence of a command.
- #command_allowed?(command, event) ⇒ Boolean
-
#event?(event, **params) ⇒ Boolean
Checks for the existence of a handled event.
- #event_allowed?(event) ⇒ Boolean
-
#expanded_prefix ⇒ Object
Helpers.
-
#get_command(command, **params) ⇒ RequestHandler
Gets the handler for a command.
-
#get_event(event, **params) ⇒ RequestHandler
Gets the handler for an event.
-
#in_event? ⇒ Boolean
Helpers for handling events.
-
#initialize(hs_url, **params) ⇒ Base
constructor
A new instance of Base.
-
#register_command(command, **params) ⇒ Object
Register a command during runtime.
-
#register_event(event, **params) ⇒ Object
Register an event during runtime.
- #room ⇒ Object
- #sender ⇒ Object
-
#sender_admin? ⇒ Boolean
Helpers for checking power levels.
- #sender_moderator? ⇒ Boolean
-
#unregister_command(command) ⇒ Object
Removes a registered command during runtime.
-
#unregister_event(command) ⇒ Object
Removes a registered event during runtime.
Methods included from Extensions
Methods included from Logging
Constructor Details
#initialize(hs_url, **params) ⇒ Base
Returns a new instance of Base.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/active_matrix/bot/base.rb', line 31 def initialize(hs_url, **params) @client = case hs_url when ActiveMatrix::Api ActiveMatrix::Client.new hs_url when ActiveMatrix::Client hs_url when %r{^https?://.*} ActiveMatrix::Client.new hs_url, **params else ActiveMatrix::Client.new_for_domain hs_url, **params end @client.on_event.add_handler { |ev| _handle_event(ev) } @client.on_invite_event.add_handler do |ev| break unless settings.accept_invites? logger.info "Received invite to #{ev[:room_id]}, joining." client.join_room(ev[:room_id]) end @event = nil logger.warn 'The bot abstraction is not fully finalized and can be expected to change.' end |
Class Attribute Details
.handlers ⇒ Object (readonly)
Returns the value of attribute handlers.
141 142 143 |
# File 'lib/active_matrix/bot/base.rb', line 141 def handlers @handlers end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
26 27 28 |
# File 'lib/active_matrix/bot/base.rb', line 26 def client @client end |
#event ⇒ Object (readonly)
Returns the value of attribute event.
26 27 28 |
# File 'lib/active_matrix/bot/base.rb', line 26 def event @event end |
#logger ⇒ Object
56 57 58 59 60 |
# File 'lib/active_matrix/bot/base.rb', line 56 def logger return @logger if instance_variable_defined?(:@logger) && @logger self.class.logger end |
Class Method Details
.all_handlers(type: :command) ⇒ Array[RequestHandler]
Retrieves all registered - including inherited - handlers for the bot
179 180 181 182 |
# File 'lib/active_matrix/bot/base.rb', line 179 def all_handlers(type: :command) parent = superclass&.all_handlers(type: type) if superclass.respond_to? :all_handlers (parent || {}).merge(@handlers.select { |_, h| type == :all || h.type == type }).compact end |
.client(&block) ⇒ Object
Registers a block to be run when configuring the client, before starting the sync
299 300 301 |
# File 'lib/active_matrix/bot/base.rb', line 299 def client(&block) @client_handler = block end |
.command(command, desc: nil, notes: nil, only: nil, **params) ⇒ Object
Due to the way blocks are handled, required parameters won’t block execution. If your command requires all parameters to be valid, you will need to check for nil yourself.
Execution will be performed with a ActiveMatrix::Bot::Request object as self. To access the bot instance, use ActiveMatrix::Bot::Request#bot
Register a bot command
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/active_matrix/bot/base.rb', line 255 def command(command, desc: nil, notes: nil, only: nil, **params, &) args = params[:args] || convert_to_lambda(&).parameters.filter_map do |type, name| case type when :req name.to_s.upcase when :opt "[#{name.to_s.upcase}]" when :rest "[#{name.to_s.upcase}...]" end end.join(' ') logger.debug "Registering command #{command} with args #{args}" add_handler( command.to_s.downcase, type: :command, args: args, desc: desc, notes: notes, only: [only].flatten.compact, & ) end |
.command?(command, ignore_inherited: false) ⇒ Boolean
Check if a command is registered
307 308 309 310 311 |
# File 'lib/active_matrix/bot/base.rb', line 307 def command?(command, ignore_inherited: false) return @handlers[command.to_s.downcase]&.command? if ignore_inherited all_handlers[command.to_s.downcase]&.command? || false end |
.disable(*opts) ⇒ Object
Same as calling ‘set :option, false` for each of the given options.
238 239 240 |
# File 'lib/active_matrix/bot/base.rb', line 238 def disable(*opts) opts.each { |key| set(key, false) } end |
.enable(*opts) ⇒ Object
Same as calling ‘set :option, true` for each of the given options.
231 232 233 |
# File 'lib/active_matrix/bot/base.rb', line 231 def enable(*opts) opts.each { |key| set(key, true) } end |
.event(event, only: nil, **_params) ⇒ Object
Currently it’s only possible to register one handler per event type
Register a Matrix event
287 288 289 290 291 292 293 294 295 296 |
# File 'lib/active_matrix/bot/base.rb', line 287 def event(event, only: nil, **_params, &) logger.debug "Registering event #{event}" add_handler( event.to_s, type: :event, only: [only].flatten.compact, & ) end |
.event?(event, ignore_inherited: false) ⇒ Boolean
Check if an event is registered
317 318 319 320 321 |
# File 'lib/active_matrix/bot/base.rb', line 317 def event?(event, ignore_inherited: false) return @handlers[event]&.event? if ignore_inherited all_handlers(type: :event)[event]&.event? || false end |
.get_command(command, ignore_inherited: false) ⇒ RequestHandler?
Retrieves the RequestHandler for a given command
328 329 330 331 332 333 334 |
# File 'lib/active_matrix/bot/base.rb', line 328 def get_command(command, ignore_inherited: false) if ignore_inherited && @handlers[command]&.command? @handlers[command] elsif !ignore_inherited && all_handlers[command]&.command? all_handlers[command] end end |
.get_event(event, ignore_inherited: false) ⇒ RequestHandler?
Retrieves the RequestHandler for a given event
341 342 343 344 345 346 347 |
# File 'lib/active_matrix/bot/base.rb', line 341 def get_event(event, ignore_inherited: false) if ignore_inherited && @handlers[event]&.event? @handlers[event] elsif !ignore_inherited && all_handlers(type: :event)[event]&.event? all_handlers(type: :event)[event] end end |
.logger ⇒ Object
62 63 64 |
# File 'lib/active_matrix/bot/base.rb', line 62 def self.logger @logger ||= ActiveMatrix.logger end |
.quit! ⇒ Object
Stops any running instance of the bot
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/active_matrix/bot/base.rb', line 372 def quit! return unless running? active_bot.logger.info "Stopping #{settings.bot_name}..." if settings.store_sync_token begin active_bot.client.api.set_account_data( active_bot.client.mxid, "dev.ananace.ruby-sdk.#{settings.bot_name}", { sync_token: active_bot.client.sync_token } ) rescue StandardError => e active_bot.logger.error "Failed to save sync token, #{e.class}: #{e}" end end active_bot.client.logout if login? active_bot.client.api.stop_inflight active_bot.client.stop_listener_thread set :active_bot, nil end |
.remove_command(command) ⇒ Object
This will only affect local commands, not ones inherited
Removes a registered command from the bot
353 354 355 356 357 358 |
# File 'lib/active_matrix/bot/base.rb', line 353 def remove_command(command) return false unless @handlers[command]&.command? @handers.delete command true end |
.remove_event(event) ⇒ Object
This will only affect local event, not ones inherited
Removes a registered event from the bot
364 365 366 367 368 369 |
# File 'lib/active_matrix/bot/base.rb', line 364 def remove_event(event) return false unless @handlers[event]&.event? @handers.delete event true end |
.reset! ⇒ Object
Reset the bot class, removing any local handlers that have been registered
170 171 172 173 |
# File 'lib/active_matrix/bot/base.rb', line 170 def reset! @handlers = {} @client_handler = nil end |
.run!(options = {}) ⇒ Object
Starts the bot up
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
# File 'lib/active_matrix/bot/base.rb', line 399 def run!( = {}, &) return if running? set bot_settings = settings.respond_to?(:bot_settings) ? settings.bot_settings : {} bot_settings.merge!( threadsafe: settings.threadsafe, client_cache: settings.client_cache, sync_filter: settings.sync_filter ) bot_settings[:auth] = if settings.access_token? { access_token: settings.access_token } else { username: settings.username, password: settings.password } end begin start_bot(bot_settings, &) ensure quit! end end |
.running? ⇒ Boolean
Check whether the self-hosted server is running or not.
425 426 427 |
# File 'lib/active_matrix/bot/base.rb', line 425 def running? active_bot? end |
.set(option, value = (not_set = true), ignore_setter = false, &block) ⇒ Object
Set a class-wide option for the bot
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/active_matrix/bot/base.rb', line 190 def set(option, value = (not_set = true), ignore_setter = false, &block) # rubocop:disable Style/OptionalBooleanParameter raise ArgumentError if block && !not_set if block value = block not_set = false end if not_set raise ArgumentError unless option.respond_to?(:each) option.each { |k, v| set(k, v) } return self end return send("#{option}=", value) if respond_to?("#{option}=") && !ignore_setter setter = proc { |val| set option, val, true } getter = proc { value } case value when Proc getter = value when Symbol, Integer, FalseClass, TrueClass, NilClass getter = value.inspect when Hash setter = proc do |val| val = value.merge val if val.is_a? Hash set option, val, true end end define_singleton("#{option}=", setter) define_singleton(option, getter) define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?" self end |
.settings ⇒ Object
Access settings defined with Base.set
136 137 138 |
# File 'lib/active_matrix/bot/base.rb', line 136 def self.settings self end |
Instance Method Details
#bot ⇒ Object
593 594 595 |
# File 'lib/active_matrix/bot/base.rb', line 593 def bot self end |
#command?(command, **params) ⇒ Boolean
Checks for the existence of a command
120 121 122 |
# File 'lib/active_matrix/bot/base.rb', line 120 def command?(command, **params) self.class.command?(command, **params) end |
#command_allowed?(command, event) ⇒ Boolean
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
# File 'lib/active_matrix/bot/base.rb', line 525 def command_allowed?(command, event) pre_event = @event return false unless command? command handler = get_command(command) return true if (handler.data[:only] || []).empty? # Avoid modifying input data for a checking method @event = ActiveMatrix::Response.new(client.api, event.dup) return false if [handler.data[:only]].flatten.compact.any? do |only| if only.is_a? Proc !instance_exec(&only) else case only.to_s.downcase.to_sym when :dm !room.dm?(members_only: true) when :admin !sender_admin? when :mod !sender_moderator? end end end true ensure @event = pre_event end |
#event?(event, **params) ⇒ Boolean
Checks for the existence of a handled event
128 129 130 |
# File 'lib/active_matrix/bot/base.rb', line 128 def event?(event, **params) self.class.event?(event, **params) end |
#event_allowed?(event) ⇒ Boolean
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/active_matrix/bot/base.rb', line 555 def event_allowed?(event) pre_event = @event return false unless event? event[:type] handler = get_event(event[:type]) return true if (handler.data[:only] || []).empty? # Avoid modifying input data for a checking method @event = ActiveMatrix::Response.new(client.api, event.dup) return false if [handler.data[:only]].flatten.compact.any? do |only| if only.is_a? Proc instance_exec(&only) else case only.to_s.downcase.to_sym when :dm !room.dm?(members_only: true) when :admin !sender_admin? when :mod !sender_moderator? end end end true ensure @event = pre_event end |
#expanded_prefix ⇒ Object
Helpers
618 619 620 621 622 |
# File 'lib/active_matrix/bot/base.rb', line 618 def return "#{settings.command_prefix}#{settings.bot_name} " if settings.bot_name? settings.command_prefix end |
#get_command(command, **params) ⇒ RequestHandler
Gets the handler for a command
103 104 105 |
# File 'lib/active_matrix/bot/base.rb', line 103 def get_command(command, **params) self.class.get_command(command, **params) end |
#get_event(event, **params) ⇒ RequestHandler
Gets the handler for an event
112 113 114 |
# File 'lib/active_matrix/bot/base.rb', line 112 def get_event(event, **params) self.class.get_event(event, **params) end |
#in_event? ⇒ Boolean
Helpers for handling events
589 590 591 |
# File 'lib/active_matrix/bot/base.rb', line 589 def in_event? !@event.nil? end |
#register_command(command, **params) ⇒ Object
Register a command during runtime
70 71 72 |
# File 'lib/active_matrix/bot/base.rb', line 70 def register_command(command, **params, &) self.class.command(command, **params, &) end |
#register_event(event, **params) ⇒ Object
Register an event during runtime
78 79 80 |
# File 'lib/active_matrix/bot/base.rb', line 78 def register_event(event, **params, &) self.class.event(event, **params, &) end |
#room ⇒ Object
597 598 599 |
# File 'lib/active_matrix/bot/base.rb', line 597 def room client.ensure_room(event[:room_id]) if in_event? end |
#sender ⇒ Object
601 602 603 |
# File 'lib/active_matrix/bot/base.rb', line 601 def sender client.get_user(event[:sender]) if in_event? end |
#sender_admin? ⇒ Boolean
Helpers for checking power levels
606 607 608 |
# File 'lib/active_matrix/bot/base.rb', line 606 def sender_admin? sender&.admin? room end |
#sender_moderator? ⇒ Boolean
610 611 612 |
# File 'lib/active_matrix/bot/base.rb', line 610 def sender_moderator? sender&.moderator? room end |
#unregister_command(command) ⇒ Object
Removes a registered command during runtime
86 87 88 |
# File 'lib/active_matrix/bot/base.rb', line 86 def unregister_command(command) self.class.remove_command(command) end |
#unregister_event(command) ⇒ Object
Removes a registered event during runtime
94 95 96 |
# File 'lib/active_matrix/bot/base.rb', line 94 def unregister_event(command) self.class.remove_event(command) end |