diff --git a/lib/addons/roller.rb b/lib/addons/roller.rb index 5a9bce7..1c522e9 100644 --- a/lib/addons/roller.rb +++ b/lib/addons/roller.rb @@ -1,30 +1,42 @@ # frozen_string_literal: true module Chronicle - module Matrix + module Addon # Roll dice and get the results - # - # @param message [hash] The message data from Matrix - def handle_roll(client, message) - msgstr = message.content[:body] - .gsub(/!roll\s*/, '') - .strip + class Roller + def self.register(bot) + addon_instance = new(bot) + addon_command = ['roll'] - room = client.ensure_room(message.room_id) + [addon_instance, addon_command] + end - res = Roller.roll(msgstr) + def initialize(bot) + @bot = bot + end - final_msg = res.reduce("") { |x,y| x+y+"\n" } + # Handle a command from the Matrix protocol + # + # @param message [hash] The message data from Matrix + def matrix_command(message) + msgstr = message.content[:body] + .gsub(/!roll\s*/, '') + .strip - room.send_notice(final_msg) - end + room = @bot.client.ensure_room(message.room_id) + + res = roll(msgstr) + + final_msg = res.reduce('') { |x, y| x + y + "\n" } + + room.send_notice(final_msg) + end - module Roller # Solve an arithmatic forumla from a string # # @param string [String] The string representation of the formula # @return Integer of the solution - def self.solve(string) + def solve(string) formatted = string.gsub(/\s+/, '') formatted = formatted.gsub(/\[[\d,]*\]/) do |a| a.scan(/\d*/).reduce(0) { |x, y| x + y.to_i } @@ -77,7 +89,7 @@ module Chronicle # @param string [String] The processed request # @param res [String] The result of the process # @return String re-formatted - def self.pretty(func, orig, string, res) + def pretty(func, orig, string, res) orig.gsub!(/[\+\-*\/]/) { |s| " #{s} " } string.gsub!(/[\+\-*\/]/) { |s| " #{s} " } "#{func.capitalize}: #{orig} (#{string}) ==> #{res}" @@ -88,7 +100,7 @@ module Chronicle # @param string [String] The string representation of the dice roll # example: 2d4+6 # @return Array of the message and the result - def self.roll(string) + def roll(string) results = [] string.gsub(/\s+/,'').split(',').each do |roll| orig = roll diff --git a/lib/addons/utils.rb b/lib/addons/utils.rb index e788d41..38bd545 100644 --- a/lib/addons/utils.rb +++ b/lib/addons/utils.rb @@ -1,56 +1,82 @@ # frozen_string_literal: true module Chronicle - module Matrix + module Addon # Ping - Pong. Useful for testing - # - # @param client [Client object] The current Matrix client connection - # @param message [Message object] The relevant message object - def handle_ping(client, message) - room = client.ensure_room message.room_id + class Ping + def self.register(bot) + addon_instance = new(bot) + addon_command = ['ping'] - room.send_notice('Pong!') + [addon_instance, addon_command] + end + + def initialize(bot) + @bot = bot + end + + # Handle a command from the Matrix protocol + # + # @param message [Message object] The relevant message object + def matrix_command(message) + room = @bot.client.ensure_room(message.room_id) + + room.send_notice('Pong!') + end end # 8-Ball: Give a random, vague response to a question - # - # @param client [Client object] The current Matrix client connection - # @param message [Message object] The relevant message object - def handle_8ball(client, message) - msgstr = message.content[:body] - .gsub(/!8ball\s*/, '') - .strip + class Eightball + def self.register(bot) + addon_instance = new(bot) + addon_command = ['8ball'] - room = client.ensure_room(message.room_id) + [addon_instance, addon_command] + end - fates = [ - 'Resoundingly, yes.', - 'Chances are good.', - 'Signs point to yes.', - 'Wheel.', - 'It is worth the attempt.', - 'Uncertainty clouds my sight.', - 'Wheel and woe.', - 'Neither wheel nor woe.', - 'Concentrate, and ask again.', - 'I cannot say for sure.', - 'The fates do not know.', - "Why are you asking me? I'm just a bot.", - 'Error: Fate API returned 404. Try again later.', - 'Woe.', - 'Chances are poor.', - 'Signs point to no.', - 'Very doubtful.', - 'Absolutely no.' - ] + def initialize(bot) + @bot = bot + end - res = if msgstr[-1] == '?' - fates.sample - else - 'You must ask a question. Try again' - end + # Handle a command from the Matrix protocol + # + # @param message [Message object] The relevant message object + def matrix_command(message) + msgstr = message.content[:body] + .gsub(/!8ball\s*/, '') + .strip - room.send_notice(res) + room = @bot.client.ensure_room(message.room_id) + + fates = [ + 'Resoundingly, yes.', + 'Chances are good.', + 'Signs point to yes.', + 'Wheel.', + 'It is worth the attempt.', + 'Uncertainty clouds my sight.', + 'Wheel and woe.', + 'Neither wheel nor woe.', + 'Concentrate, and ask again.', + 'I cannot say for sure.', + 'The fates do not know.', + "Why are you asking me? I'm just a bot.", + 'Error: Fate API returned 404. Try again later.', + 'Woe.', + 'Chances are poor.', + 'Signs point to no.', + 'Very doubtful.', + 'Absolutely no.' + ] + + res = if msgstr[-1] == '?' + fates.sample + else + 'You must ask a question. Try again' + end + + room.send_notice(res) + end end end end diff --git a/lib/chronicle_bot.rb b/lib/chronicle_bot.rb index a261bf8..db76a22 100755 --- a/lib/chronicle_bot.rb +++ b/lib/chronicle_bot.rb @@ -4,13 +4,13 @@ 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 - # Require any addons - Dir[File.join(__dir__, 'addons', '*.rb')].each do |file| - require file - end - # A filter to simplify syncs BOT_FILTER = { presence: { types: [] }, @@ -30,23 +30,6 @@ module Chronicle # 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 @@ -65,11 +48,68 @@ module Chronicle # The bot class ChronicleBot - include Matrix + 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 + 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 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 @@ -95,36 +135,6 @@ module Chronicle 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