The `help_command` method for each addon/the bot were not returning the help message, but were instead sending the help messages themselves. Update the logic to simply return the help message string.
187 lines
4.8 KiB
Ruby
Executable file
187 lines
4.8 KiB
Ruby
Executable file
# frozen_string_literal: true
|
|
|
|
require 'faraday'
|
|
require 'json'
|
|
require 'matrix_sdk'
|
|
|
|
# Require any addons
|
|
Dir[File.join(__dir__, 'addons', '*.rb')].each do |file|
|
|
require file
|
|
end
|
|
|
|
# Chronicle Bot
|
|
module Chronicle
|
|
# A filter to simplify syncs
|
|
BOT_FILTER = {
|
|
presence: { types: [] },
|
|
account_data: { types: [] },
|
|
room: {
|
|
ephemeral: { types: [] },
|
|
state: {
|
|
types: ['m.room.*'],
|
|
lazy_load_members: true
|
|
},
|
|
timeline: {
|
|
types: ['m.room.message']
|
|
},
|
|
account_data: { types: [] }
|
|
}
|
|
}.freeze
|
|
|
|
# Chronicle Bot for Matrix
|
|
module Matrix
|
|
# Begin the beast
|
|
def self.start
|
|
unless ENV["CHRONICLE_HOMESERVER"]
|
|
raise "Export your homeserver URL to CHRONICLE_HOMESERVER"
|
|
end
|
|
|
|
unless ENV["CHRONICLE_ACCESS_TOKEN"]
|
|
raise "Export your access token to CHRONICLE_ACCESS_TOKEN"
|
|
end
|
|
|
|
if ENV["CHRONICLE_DEBUG"]
|
|
Thread.abort_on_exception = true
|
|
MatrixSdk.debug!
|
|
end
|
|
|
|
bot = ChronicleBot.new(
|
|
ENV["CHRONICLE_HOMESERVER"],
|
|
ENV["CHRONICLE_ACCESS_TOKEN"]
|
|
)
|
|
|
|
bot.run
|
|
end
|
|
|
|
# The bot
|
|
class ChronicleBot
|
|
attr_reader :all_commands, :cmd_prefix
|
|
|
|
def initialize(hs_url, access_token)
|
|
@hs_url = hs_url
|
|
@token = access_token
|
|
|
|
@cmd_prefix = '!'
|
|
@all_commands = {}
|
|
@allowed_commands = {}
|
|
|
|
register_commands
|
|
available_commands(self, %w[listcommands help])
|
|
end
|
|
|
|
# All available commands
|
|
def available_commands(addon, commands)
|
|
commands.each do |command|
|
|
@all_commands[command] = addon
|
|
end
|
|
end
|
|
|
|
def client
|
|
@client ||= MatrixSdk::Client.new(
|
|
@hs_url,
|
|
access_token: @token,
|
|
client_cache: :all
|
|
)
|
|
end
|
|
|
|
def deep_copy(hash)
|
|
Marshal.load(Marshal.dump(hash))
|
|
end
|
|
|
|
def disable_commands(*commands)
|
|
commands.each do |command|
|
|
@all_commands.delete(command)
|
|
end
|
|
end
|
|
|
|
def help_command(message)
|
|
pfx = @cmd_prefix
|
|
cmd = message.content[:body].split(/\s+/)[1].gsub(/#{pfx}/, '')
|
|
|
|
case cmd
|
|
when 'listcommands'
|
|
'!listcommands: List available commands managed by this bot'
|
|
else
|
|
'Try !listcommands or !help'
|
|
end
|
|
end
|
|
|
|
# Handle a command from the Matrix protocol
|
|
#
|
|
# @param message [Message object] The relevant message object
|
|
def matrix_command(message)
|
|
pfx = @cmd_prefix
|
|
cmd = message.content[:body].split(/\s+/)[0].gsub(/#{pfx}/, '')
|
|
|
|
res = 'Invalid command'
|
|
|
|
res = case cmd
|
|
when 'listcommands'
|
|
"Currently available commands: #{@all_commands.keys.sort.join(', ')}"
|
|
when 'help'
|
|
if message.content[:body].split(/\s+/).count <= 1
|
|
'!help: Get help for a specific command' \
|
|
"\nUsage: !help COMMAND"
|
|
else
|
|
second_cmd = message.content[:body].split(/\s+/)[1]
|
|
.gsub(/#{pfx}/, '')
|
|
@all_commands[second_cmd.strip].help_command(message)
|
|
end
|
|
end
|
|
|
|
room = @client.ensure_room(message.room_id)
|
|
room.send_notice(res)
|
|
end
|
|
|
|
def on_message(message)
|
|
return unless message.content[:msgtype] == 'm.text'
|
|
|
|
msgstr = message.content[:body]
|
|
roomid = message.room_id
|
|
cmds = @all_commands.keys.join('|')
|
|
|
|
return unless msgstr =~ /^#{@cmd_prefix}#{cmds}\s*/
|
|
|
|
msgstr.match(/^#{@cmd_prefix}(#{cmds})\s*/) do |m|
|
|
@all_commands[m.to_s[1..-1].strip].matrix_command(message)
|
|
end
|
|
end
|
|
|
|
def register_commands
|
|
Chronicle::Addon.constants.each do |addon|
|
|
cmd = Object.const_get("Chronicle::Addon::#{addon.to_s}")
|
|
|
|
if cmd.methods.include?(:register)
|
|
instance, commands = cmd.send(:register, self)
|
|
|
|
available_commands(instance, commands)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Run Chronicle
|
|
def run
|
|
# Join all invited rooms
|
|
client.on_invite_event.add_handler { |ev| client.join_room(ev[:room_id]) }
|
|
|
|
# Run an empty sync to get to a `since` token without old data.
|
|
# Storing the `since` token is also valid for bot use-cases, but in the
|
|
# case of ping responses there's never any need to reply to old data.
|
|
empty_sync = deep_copy(BOT_FILTER)
|
|
empty_sync[:room].map { |_k, v| v[:types] = [] }
|
|
client.sync filter: empty_sync
|
|
|
|
# Read all message events
|
|
client.on_event.add_handler('m.room.message') { |ev| on_message(ev) }
|
|
|
|
loop do
|
|
begin
|
|
client.sync filter: BOT_FILTER
|
|
rescue MatrixSdk::MatrixError => e
|
|
puts e
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|