class Autoop
Constants
- ChannelReply
- DB_TOTALS_MIGRATED_KEY
- DEFAULT_NICKS
- GLOBAL_TOTAL_KEY
- GLOBAL_TOTAL_PLUGIN_KEY
- IRC_CTRL
- IRC_RESET
- JOIN_ANNOUNCE_FALLBACK_SEC
- PLUGIN_NAME
- REPLY_TAG
- STYLE_NICK
- STYLE_NUMBER
- STYLE_TEXT
- STYLE_TITLE
Public Class Methods
Source
# File plugins/autoop.rb, line 130 def self.add_nick(state, key, nick) nick = normalize_nick(nick) ensure_channel(state, key) if nick_list(state, key).any? { |listed| entry_redundant?(nick, listed) } return [state, "#{nick} is already on the auto op list.", false] end nick_list(state, key) << nick [state, "Added #{nick} to the auto op list.", true] end
Source
# File plugins/autoop.rb, line 146 def self.add_nick_with_op(state, key, nick, user_is_opped: nil) state, message, added = add_nick(state, key, nick) op_needed = should_op_on_add?(added: added, user_is_opped: user_is_opped) [state, message, op_needed] end
Source
# File plugins/autoop.rb, line 248 def self.announcement_body(nick, count) AutoopReport.announcement_body(nick, count) end
Source
# File plugins/autoop.rb, line 315 def self.build_join_announcement_result(pending, lag_ms:, token:) { ms: lag_ms, token: token, announcement: complete_auto_op_announcement(pending, lag_ms: lag_ms), reply_target: reply_target(pending) } end
Source
# File plugins/autoop.rb, line 209 def self.command_allowed?(user_is_channel_op) user_is_channel_op end
Source
# File plugins/autoop.rb, line 244 def self.command_reply_title(message) AutoopReport.command_reply_title(message) end
Source
# File plugins/autoop.rb, line 298 def self.complete_auto_op_announcement(pending, lag_ms:, ping_ms: nil, server: nil) format_announcement( pending[:nick], pending[:count], lag_ms: lag_ms, ping_ms: ping_ms || pending[:ping_ms], server: server || pending[:server] ) end
Source
# File plugins/autoop.rb, line 69 def self.ensure_channel(state, key) state[key] ||= { "nicks" => DEFAULT_NICKS.dup } migrate_legacy_counts!(state, key) state[key] end
Source
# File plugins/autoop.rb, line 124 def self.entry_redundant?(new_entry, listed_entry) return true if listed_entry.casecmp?(new_entry) NickPattern.match?(new_entry, listed_entry) || NickPattern.match?(listed_entry, new_entry) end
Source
# File plugins/autoop.rb, line 324 def self.finalize_join_announcement!(token) IrcLag.take_pending_reply(token) end
Source
# File plugins/autoop.rb, line 328 def self.finalize_join_batch!(batch_token) AutoopJoinProbe.finalize_batch!(batch_token) end
Source
# File plugins/autoop.rb, line 115 def self.find_listed_nick(state, key, nick) nick = normalize_nick(nick) list = nick_list(state, key) exact = list.find { |listed| listed.casecmp?(nick) } return exact if exact list.find { |listed| NickPattern.match?(nick, listed) } end
Source
# File plugins/autoop.rb, line 152 def self.find_user_by_nick(users, nick) target = normalize_nick(nick).downcase users.find { |user| user.nick.casecmp?(target) } end
Source
# File plugins/autoop.rb, line 252 def self.format_announcement(nick, count, lag_ms: 0, ping_ms: nil, server: nil) AutoopReport.format_announcement(nick, count, lag_ms: lag_ms, ping_ms: ping_ms, server: server) end
Source
# File plugins/autoop.rb, line 240 def self.format_command_reply(message, lag_ms: 0, ping_ms: nil, server: nil) AutoopReport.format_command_reply(message, lag_ms: lag_ms, ping_ms: ping_ms, server: server) end
Source
# File plugins/autoop.rb, line 256 def self.format_nick_list(state, key, lag_ms: 0, ping_ms: nil, server: nil) AutoopReport.format_nick_list(nick_list(state, key), lag_ms: lag_ms, ping_ms: ping_ms, server: server) end
Source
# File plugins/autoop.rb, line 232 def self.format_reply_card(**kwargs) AutoopReport.format_reply_card(**kwargs) end
Source
# File plugins/autoop.rb, line 236 def self.format_status_message(text, title:, lag_ms: 0, ping_ms: nil, server: nil) AutoopReport.format_status_message(text, title: title, lag_ms: lag_ms, ping_ms: ping_ms, server: server) end
Source
# File plugins/autoop.rb, line 75 def self.global_op_total(state) state.fetch(GLOBAL_TOTAL_KEY, 0).to_i end
Source
# File plugins/autoop.rb, line 79 def self.increment_global_op_count(state) total = global_op_total(state) + 1 state[GLOBAL_TOTAL_KEY] = total total end
Source
# File plugins/autoop.rb, line 175 def self.increment_op_count(state, key, _nick) ensure_channel(state, key) [state, increment_global_op_count(state)] end
Source
# File plugins/autoop.rb, line 224 def self.irc_color(fg, bg = nil) AutoopReport.irc_color(fg, bg) end
Source
# File plugins/autoop.rb, line 217 def self.lag_ms_from_bot(bot = nil) stored = bot&.data&.fetch(:irc_lag_ms, nil) return stored.to_i unless stored.nil? IrcLag.current_ms end
Source
# File plugins/autoop.rb, line 196 def self.load_global_total_into!(state) value = RabbotDb.get_plugin_value(plugin: PLUGIN_NAME, key: GLOBAL_TOTAL_PLUGIN_KEY) state[GLOBAL_TOTAL_KEY] = value.to_i unless value.nil? end
Source
# File plugins/autoop.rb, line 157 def self.manage_add_command(state, key, nick, user_is_opped: nil) state, message, op_needed = add_nick_with_op(state, key, nick, user_is_opped: user_is_opped) { state: state, message: message, op_needed: op_needed } end
Source
# File plugins/autoop.rb, line 260 def self.manage_command(state, key, args) parsed = parse_command(args) return parsed[:error] if parsed[:error] case parsed[:action] when :add _state, message, _op_needed = add_nick(state, key, parsed[:nick]) message when :rem _state, message = remove_nick(state, key, parsed[:nick]) message when :list format_nick_list(state, key) end end
Source
# File plugins/autoop.rb, line 342 def self.map_join_probe_items(items) items.map do |item| build_join_announcement_result(item[:pending], lag_ms: item[:lag_ms], token: item[:batch_token]) end end
Source
# File plugins/autoop.rb, line 180 def self.migrate_db_totals_to_global! return if RabbotDb.get_plugin_value(plugin: PLUGIN_NAME, key: DB_TOTALS_MIGRATED_KEY) == "1" sum = RabbotDb.connection.get_first_value("SELECT COALESCE(SUM(autoop_total), 0) FROM channels").to_i if sum.positive? current = RabbotDb.get_plugin_value(plugin: PLUGIN_NAME, key: GLOBAL_TOTAL_PLUGIN_KEY).to_i RabbotDb.set_plugin_value( plugin: PLUGIN_NAME, key: GLOBAL_TOTAL_PLUGIN_KEY, value: (current + sum).to_s ) RabbotDb.connection.execute("UPDATE channels SET autoop_total = 0") end RabbotDb.set_plugin_value(plugin: PLUGIN_NAME, key: DB_TOTALS_MIGRATED_KEY, value: "1") end
Source
# File plugins/autoop.rb, line 85 def self.migrate_legacy_counts!(state, key) channel = state[key] return unless channel.is_a?(Hash) migrated = 0 if channel.key?("counts") legacy = channel["counts"] migrated += legacy.values.sum if legacy.is_a?(Hash) channel.delete("counts") end if channel.key?("total") migrated += channel["total"].to_i channel.delete("total") end return if migrated.zero? state[GLOBAL_TOTAL_KEY] = global_op_total(state) + migrated end
Source
# File plugins/autoop.rb, line 370 def initialize(*args) super @store = {} @loaded_keys = Set.new RabbotDb.migrate_legacy_autoop_json!(default_nicks: DEFAULT_NICKS) self.class.migrate_db_totals_to_global! self.class.load_global_total_into!(@store) end
Calls superclass method
Source
# File plugins/autoop.rb, line 106 def self.nick_list(state, key) ensure_channel(state, key)["nicks"] end
Source
# File plugins/autoop.rb, line 110 def self.nick_on_list?(state, key, nick) nick = normalize_nick(nick) nick_list(state, key).any? { |listed| NickPattern.match?(nick, listed) } end
Source
# File plugins/autoop.rb, line 213 def self.non_op_message(lag_ms: 0, ping_ms: nil, server: nil) AutoopReport.non_op_message(lag_ms: lag_ms, ping_ms: ping_ms, server: server) end
Source
# File plugins/autoop.rb, line 61 def self.normalize_nick(nick) Normalize.nick(nick) end
Source
# File plugins/autoop.rb, line 228 def self.number_style_colors AutoopReport.number_style_colors end
Source
# File plugins/autoop.rb, line 65 def self.parse_command(args) ListCommand.parse_add_rem(args, usage_message: usage_message) end
Source
# File plugins/autoop.rb, line 280 def self.prepare_auto_op(state, key, nick, lag_ms: 0, ping_ms: nil, server: nil) pending = prepare_auto_op_pending(state, key, nick) { count: pending[:count], announcement: complete_auto_op_announcement( pending, lag_ms: lag_ms, ping_ms: ping_ms, server: server ) } end
Source
# File plugins/autoop.rb, line 293 def self.prepare_auto_op_pending(state, key, nick) _state, count = increment_op_count(state, key, nick) { nick: normalize_nick(nick), count: count } end
Source
# File plugins/autoop.rb, line 348 def self.process_join_lag_probe_reply!(params, received_at:) map_join_probe_items( AutoopJoinProbe.process_lag_probe_reply!(params, received_at: received_at) ) end
Source
# File plugins/autoop.rb, line 354 def self.process_user_pong_reply!(params:, received_at:) map_join_probe_items( AutoopJoinProbe.process_user_pong_reply!(params: params, received_at: received_at) ) end
Source
# File plugins/autoop.rb, line 162 def self.remove_nick(state, key, nick) nick = normalize_nick(nick) ensure_channel(state, key) listed = find_listed_nick(state, key, nick) unless listed return [state, "#{nick} is not on the auto op list."] end nick_list(state, key).delete(listed) [state, "Removed #{listed} from the auto op list."] end
Source
# File plugins/autoop.rb, line 308 def self.reply_target(pending) channel = pending[:channel] return ChannelReply.new(channel) if channel pending[:message] end
Source
# File plugins/autoop.rb, line 201 def self.save_global_total!(state) RabbotDb.set_plugin_value( plugin: PLUGIN_NAME, key: GLOBAL_TOTAL_PLUGIN_KEY, value: global_op_total(state).to_s ) end
Source
# File plugins/autoop.rb, line 276 def self.should_auto_op?(state, key, nick) nick_on_list?(state, key, nick) end
Source
# File plugins/autoop.rb, line 142 def self.should_op_on_add?(added:, user_is_opped:) added && !user_is_opped.nil? && !user_is_opped end
Source
# File plugins/autoop.rb, line 360 def self.stale_join_announcements(max_age_sec:, now:) map_join_probe_items( AutoopJoinProbe.stale_announcements(max_age_sec: max_age_sec, now: now) ) end
Source
# File plugins/autoop.rb, line 332 def self.start_join_probe(nick:, count:, channel:, server:, sent_at:) AutoopJoinProbe.attach( nick: nick, count: count, channel: channel, server: server, sent_at: sent_at ) end
Source
# File plugins/autoop.rb, line 57 def self.storage_key(network, channel) "#{network}/#{channel.to_s.downcase}" end
Source
# File plugins/autoop.rb, line 53 def self.usage_message "Usage: !rabbot op <add|rem|list> [nick]" end
Source
# File plugins/autoop.rb, line 366 def self.user_ping_command(nick:, token:) IrcUserPing.user_ping_command(nick: nick, token: token) end
Public Instance Methods
Source
# File plugins/autoop.rb, line 448 def execute(m, args) lag_ms = self.class.lag_ms_from_bot(bot) unless self.class.command_allowed?(m.channel.opped?(m.user)) themed_flood_safe_reply(m, self.class.non_op_message(lag_ms: lag_ms)) return end key = storage_key_for(m.channel) ensure_loaded(key) parsed = self.class.parse_command(args) if parsed[:error] themed_flood_safe_reply(m, parsed[:error]) return end case parsed[:action] when :list themed_flood_safe_reply(m, self.class.format_nick_list(@store, key, lag_ms: lag_ms)) when :add target = self.class.find_user_by_nick(m.channel.user_list, parsed[:nick]) user_is_opped = target ? m.channel.opped?(target) : nil result = self.class.manage_add_command(@store, key, parsed[:nick], user_is_opped: user_is_opped) @store = result[:state] save_channel(key) themed_flood_safe_reply(m, self.class.format_command_reply(result[:message], lag_ms: lag_ms)) m.channel.op(target) if result[:op_needed] && m.channel.opped?(bot) when :rem @store, message = self.class.remove_nick(@store, key, parsed[:nick]) save_channel(key) themed_flood_safe_reply(m, self.class.format_command_reply(message, lag_ms: lag_ms)) end end
Source
# File plugins/autoop.rb, line 440 def flush_stale_join_announcements now = Process.clock_gettime(Process::CLOCK_MONOTONIC) stale = self.class.stale_join_announcements(max_age_sec: JOIN_ANNOUNCE_FALLBACK_SEC, now: now) stale.group_by { |processed| processed[:token] }.each_value do |batch| deliver_join_announcements(batch) end end
Source
# File plugins/autoop.rb, line 379 def listen(m) return if m.user.nick == bot.nick key = storage_key_for(m.channel) ensure_loaded(key) return unless self.class.should_auto_op?(@store, key, m.user.nick) return unless m.channel.opped?(bot) pending = self.class.prepare_auto_op_pending(@store, key, m.user.nick) save_channel(key) self.class.save_global_total!(@store) m.channel.op(m.user) sent_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) server = bot.config.server probe = self.class.start_join_probe( nick: pending[:nick], count: pending[:count], channel: m.channel, server: server, sent_at: sent_at ) return unless probe[:send_probes] IrcUserPing.register!(nick: probe[:nick], sent_at: probe[:sent_at], context: probe[:batch_token]) bot.irc.send(self.class.user_ping_command(nick: probe[:nick], token: probe[:batch_token])) bot.irc.send(AutoopJoinProbe.lag_probe_command(probe[:batch_token])) end
Source
# File plugins/autoop.rb, line 417 def on_pong(m) received_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) ms = IrcLag.record_pong!(m.params, received_at: received_at) if ms IrcLag.sync_bot_lag!(bot, ms: ms) return end processed = self.class.process_user_pong_reply!(params: m.params, received_at: received_at) deliver_join_announcements(processed) unless processed.empty? end
Source
# File plugins/autoop.rb, line 429 def on_unknown_command(m) processed = self.class.process_join_lag_probe_reply!( m.params, received_at: Process.clock_gettime(Process::CLOCK_MONOTONIC) ) return if processed.empty? IrcLag.sync_bot_lag!(bot, ms: processed.first[:ms]) deliver_join_announcements(processed) end
Source
# File plugins/autoop.rb, line 408 def poll_lag_ping now = Process.clock_gettime(Process::CLOCK_MONOTONIC) return unless IrcLag.due_for_ping?(IrcLag.last_ping_at, now: now) sent_at = now IrcLag.register_ping!(sent_at) bot.irc.send(IrcLag.ping_command(timestamp: sent_at)) end