chronicle_bot: An ambitious chat bot for Matrix
This commit is contained in:
parent
24bd7553fa
commit
1a422b65d0
1 changed files with 130 additions and 0 deletions
130
lib/chronicle_bot.rb
Executable file
130
lib/chronicle_bot.rb
Executable file
|
@ -0,0 +1,130 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'faraday'
|
||||
require 'json'
|
||||
require 'matrix_sdk'
|
||||
|
||||
# Chronicle Bot
|
||||
module Chronicle
|
||||
# Require any addons
|
||||
Dir[File.join(__dir__, 'addons', '*.rb')].each do |file|
|
||||
require file
|
||||
end
|
||||
|
||||
# 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
|
||||
@@default_allowed_commands = %w[ping]
|
||||
@@room_allowed_commands = {}
|
||||
|
||||
# Update allowed commands
|
||||
def add_allowed_commands(cmds, msgid='')
|
||||
if msgid
|
||||
@@room_allowed_commands[msgid].concat(cmds)
|
||||
else
|
||||
@@room_allowed_commands.each { |_,v| v.concat(cmds) }
|
||||
end
|
||||
end
|
||||
|
||||
# Establish or return allowed commands for a room
|
||||
def allowed_commands(msgid)
|
||||
@@room_allowed_commands[msgid] ||= @@default_allowed_commands
|
||||
end
|
||||
|
||||
# Begin the beast
|
||||
def self.start(args)
|
||||
unless args.length >= 2
|
||||
raise "Usage: #{$PROGRAM_NAME} [-d] homeserver_url access_token"
|
||||
end
|
||||
|
||||
if args.first == '-d'
|
||||
Thread.abort_on_exception = true
|
||||
MatrixSdk.debug!
|
||||
args.shift
|
||||
end
|
||||
|
||||
bot = ChronicleBot.new args[0], args[1]
|
||||
bot.run
|
||||
end
|
||||
|
||||
# The bot
|
||||
class ChronicleBot
|
||||
include Matrix
|
||||
|
||||
def initialize(hs_url, access_token)
|
||||
@hs_url = hs_url
|
||||
@token = access_token
|
||||
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
|
||||
|
||||
def on_message(message)
|
||||
return unless message.content[:msgtype] == 'm.text'
|
||||
|
||||
msgstr = message.content[:body]
|
||||
msgid = message.room_id
|
||||
cmds = allowed_commands(msgid).join('|')
|
||||
|
||||
return unless msgstr =~ /^!#{cmds}\s*/
|
||||
|
||||
msgstr.match(/^!(#{cmds})\s*/) do |m|
|
||||
send(
|
||||
"handle_#{m.to_s[1..-1].strip}",
|
||||
client,
|
||||
message
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def client
|
||||
@client ||= MatrixSdk::Client.new(
|
||||
@hs_url,
|
||||
access_token: @token,
|
||||
client_cache: :none
|
||||
)
|
||||
end
|
||||
|
||||
def deep_copy(hash)
|
||||
Marshal.load(Marshal.dump(hash))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue