Class: Twittbot::Bot
- Inherits:
-
Object
- Object
- Twittbot::Bot
- Includes:
- Thor::Shell
- Defined in:
- lib/twittbot/bot.rb
Overview
Class providing the streaming connections and callback logic for the bot.
Instance Method Summary collapse
-
#already_authed? ⇒ Boolean
Whether the bot is already authenticated or not.
-
#auth ⇒ Object
Authenticates an account with Twitter.
-
#check_config ⇒ Object
Checks some configuration values, e.g.
-
#cron(task_name) ⇒ Object
Runs the task ‘task_name`.
-
#do_callbacks(callback_type, object, options = {}) ⇒ Object
Runs callbacks.
-
#do_direct_message(dm, opts = {}) ⇒ Object
Processes a direct message.
- #do_periodic ⇒ Object
-
#handle_stream_object(object, type) ⇒ Object
Handles a object yielded from a Twitter::Streaming::Client.
-
#initialize(options = {}) ⇒ Bot
constructor
A new instance of Bot.
-
#load_bot_code ⇒ Object
Loads the bot’s actual code which is stored in the bot’s
libsubdirectory. - #modify_admin(screen_name, action = :add) ⇒ Object
-
#save_config ⇒ Object
Saves the bot’s config (i.e. not the botpart ones).
-
#start ⇒ Object
Starts the bot.
Constructor Details
#initialize(options = {}) ⇒ Bot
Returns a new instance of Bot.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/twittbot/bot.rb', line 15 def initialize( = {}) @options = { current_dir: FileUtils.pwd } $bot = { botparts: [], callbacks: {}, commands: {}, config: Twittbot::DEFAULT_BOT_CONFIG.merge( YAML.load_file(File.("./#{Twittbot::CONFIG_FILE_NAME}", @options[:current_dir])) ), periodic: [], save_config: true, tasks: {}, stream: .fetch("stream", true) } load_bot_code at_exit do save_config $bot[:botparts].each { |b| b.save_config } end if $bot[:save_config] end |
Instance Method Details
#already_authed? ⇒ Boolean
Returns whether the bot is already authenticated or not.
270 271 272 |
# File 'lib/twittbot/bot.rb', line 270 def already_authed? !($bot[:config][:access_token].empty? or $bot[:config][:access_token_secret].empty?) end |
#auth ⇒ Object
Authenticates an account with Twitter.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/twittbot/bot.rb', line 42 def auth require 'oauth' say "This will reset your current access tokens.", :red if already_authed? # get the request token URL callback = OAuth::OUT_OF_BAND consumer = OAuth::Consumer.new $bot[:config][:consumer_key], $bot[:config][:consumer_secret], site: Twitter::REST::Client::BASE_URL, scheme: :header request_token = consumer.get_request_token(oauth_callback: callback) url = request_token.(oauth_callback: callback) puts "Open this URL in a browser: #{url}" pin = '' until pin =~ /^\d+$/ print "Enter PIN =>" pin = $stdin.gets.strip end access_token = request_token.get_access_token(oauth_verifier: pin) $bot[:config][:access_token] = access_token.token $bot[:config][:access_token_secret] = access_token.secret # get the bot's user name (screen_name) and print it to the console $bot[:config][:screen_name] = get_screen_name access_token puts "Hello, #{$bot[:config][:screen_name]}!" end |
#check_config ⇒ Object
Checks some configuration values, e.g. if the bot is already authenticated with Twitter
180 181 182 183 184 185 |
# File 'lib/twittbot/bot.rb', line 180 def check_config unless already_authed? say "Please authenticate using `twittbot auth' first.", :red raise 'Not authenticated' end end |
#cron(task_name) ⇒ Object
Runs the task ‘task_name`.
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/twittbot/bot.rb', line 131 def cron(task_name) task = $bot[:tasks][task_name] unless task say "Task \"#{task_name}\" does not exist. Use \"twittbot cron list\" for a list of available tasks." return end #check_config init_clients task[:block].call end |
#do_callbacks(callback_type, object, options = {}) ⇒ Object
Runs callbacks.
230 231 232 233 234 235 |
# File 'lib/twittbot/bot.rb', line 230 def do_callbacks(callback_type, object, = {}) return if $bot[:callbacks][callback_type].nil? $bot[:callbacks][callback_type].each do |c| c[:block].call object, end end |
#do_direct_message(dm, opts = {}) ⇒ Object
Processes a direct message.
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/twittbot/bot.rb', line 251 def (dm, opts = {}) return if dm.sender.screen_name == $bot[:config][:screen_name] return do_callbacks(:direct_message, dm, opts) unless dm.text.start_with? $bot[:config][:dm_command_prefix] dm_text = dm.text.sub($bot[:config][:dm_command_prefix], '').strip return if dm_text.empty? return unless /(?<command>[A-Za-z0-9]+)(?:\s*)(?<args>.*)/m =~ dm_text command = Regexp.last_match(:command).to_sym args = Regexp.last_match :args cmd = $bot[:commands][command] return say_status :dm, "#{dm.sender.screen_name} tried to issue non-existent command :#{command}, ignoring", :cyan if cmd.nil? return say_status :dm, "#{dm.sender.screen_name} tried to issue admin command :#{command}, ignoring", :cyan if cmd[:admin] and !dm.sender.admin? say_status :dm, "#{dm.sender.screen_name} issued command :#{command}", :cyan cmd[:block].call(args, dm.sender) end |
#do_periodic ⇒ Object
237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/twittbot/bot.rb', line 237 def do_periodic $bot[:periodic].each_with_index do |h, i| h[:remaining] = if h[:remaining] - 1 <= 0 h[:block].call h[:interval] else h[:remaining] - 1 end $bot[:periodic][i] = h end end |
#handle_stream_object(object, type) ⇒ Object
Handles a object yielded from a Twitter::Streaming::Client.
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 |
# File 'lib/twittbot/bot.rb', line 190 def handle_stream_object(object, type) opts = { stream_type: type } case object when Twitter::Streaming::FriendList # object: Array with IDs do_callbacks :friend_list, object when Twitter::Tweet # object: Twitter::Tweet is_mention = (object.user.screen_name != $bot[:config][:screen_name] and object.text.include?("@" + $bot[:config][:screen_name]) and not object.retweet?) do_callbacks :retweet, object, opts if object.retweet? and object.retweeted_tweet.user.screen_name == $bot[:config][:screen_name] do_callbacks :mention, object, opts if is_mention do_callbacks :tweet, object, opts.merge({ mention: is_mention, retweet: object.retweet?, favorite: object.favorited? }) when Twitter::Streaming::Event case object.name when :follow, :favorite # :follow -- object: Twitter::Streaming::Event(name: :follow, source: Twitter::User, target: Twitter::User) # :favorite -- object: Twitter::Streaming::Event(name: :favorite, source: Twitter::User, target: Twitter::User, target_object: Twitter::Tweet) do_callbacks object.name, object, opts else puts "no handler for #{object.class.to_s}/#{object.name}\n -- object data:" require 'pp' pp object do_callbacks object.name, object, opts end when Twitter::DirectMessage object, opts when Twitter::Streaming::DeletedTweet do_callbacks :deleted, object, opts else puts "no handler for #{object.class.to_s}\n -- object data:" require 'pp' pp object end end |
#load_bot_code ⇒ Object
Loads the bot’s actual code which is stored in the bot’s lib subdirectory.
162 163 164 165 166 167 168 |
# File 'lib/twittbot/bot.rb', line 162 def load_bot_code load_special_tasks files = Dir["#{File.('./lib', @options[:current_dir])}/**/*"] files.each do |file| require_relative file.sub(/\.rb$/, '') if file.end_with? '.rb' end end |
#modify_admin(screen_name, action = :add) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/twittbot/bot.rb', line 145 def modify_admin(screen_name, action = :add) init_clients user = $bot[:client].user screen_name case action when :add $bot[:config][:admins] << user.id unless $bot[:config][:admins].include? user.id when :del, :delete $bot[:config][:admins].delete user.id if $bot[:config][:admins].include? user.id else say "Unknown action " + action.to_s, :red end rescue Twitter::Error::NotFound say "User not found.", :red end |
#save_config ⇒ Object
Saves the bot’s config (i.e. not the botpart ones).
171 172 173 174 175 176 177 |
# File 'lib/twittbot/bot.rb', line 171 def save_config config = $bot[:config].clone config.delete :client File.open "./#{Twittbot::CONFIG_FILE_NAME}", 'w' do |f| f.write config.to_yaml end end |
#start ⇒ Object
Starts the bot.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/twittbot/bot.rb', line 72 def start check_config init_clients if $bot[:stream] puts "connecting to streaming APIs" @userstream_thread ||= Thread.new do loop do begin puts "connected to user stream" @streamer.user do |obj| handle_stream_object obj, :user end rescue => e puts "lost user stream connection: " + e. end puts "reconnecting in #{Twittbot::RECONNECT_WAIT_TIME} seconds..." sleep Twittbot::RECONNECT_WAIT_TIME end end @tweetstream_thread ||= Thread.new do loop do begin puts "connected to tweet stream" @streamer.filter track: $bot[:config][:track].join(",") do |obj| handle_stream_object obj, :filter end rescue puts "lost tweet stream connection: " + e. end puts "reconnecting in #{Twittbot::RECONNECT_WAIT_TIME} seconds..." sleep Twittbot::RECONNECT_WAIT_TIME end end end @periodic_thread ||= Thread.new do loop do begin Thread.new { do_periodic } rescue => _ end sleep 60 end end do_callbacks :load, nil if $bot[:stream] @userstream_thread.join @tweetstream_thread.join end @periodic_thread.join end |