rumpy 0.9.17 → 0.9.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +79 -50
- data/lib/rumpy.rb +118 -106
- metadata +4 -4
    
        data/README.rdoc
    CHANGED
    
    | @@ -1,61 +1,90 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            = Welcome to Rumpy
         | 
| 2 2 |  | 
| 3 3 | 
             
            Rumpy is some kind of framework to make up your own jabber bot quickly.
         | 
| 4 4 | 
             
            It uses {ActiveRecord}[https://github.com/rails/rails/tree/master/activerecord] and {XMPP4R}[http://home.gna.org/xmpp4r/].
         | 
| 5 5 |  | 
| 6 | 
            -
            Our goal is 'DO NOT REINVENT THE WHEEL' | 
| 6 | 
            +
            Our goal is <b>'DO NOT REINVENT THE WHEEL'</b>.
         | 
| 7 7 |  | 
| 8 | 
            -
             | 
| 8 | 
            +
            = Features
         | 
| 9 9 |  | 
| 10 | 
            -
            * Forget about xmpp-related things. Just set your login  | 
| 10 | 
            +
            * Forget about xmpp-related things. Just set your login and password.
         | 
| 11 11 | 
             
            * Forget about database-related things. Just set your database preferences.
         | 
| 12 12 | 
             
            * Write logic using ActiveRecord and callback functions.
         | 
| 13 13 |  | 
| 14 | 
            -
             | 
| 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 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
                 | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
               | 
| 46 | 
            -
             | 
| 47 | 
            -
               | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 14 | 
            +
            = Getting started
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            == Configs
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Rumpy uses 3 configs:
         | 
| 19 | 
            +
            +database.yml+  ::  Your bot's database preferences.
         | 
| 20 | 
            +
            +lang.yml+      ::  Your bot's responces. Append to existing keys more answers and use them like <tt>@lang['someanswer']</tt>. There *MUST* be at least 3 keys: +hello+ (<em>used when somebody adds bot</em>), +stranger+ (<em>used when somebody trying to speak with bot without authorization</em>) and +authorized+ (<em>used when bot gets authorization</em>).
         | 
| 21 | 
            +
            +xmpp.yml+      ::  Your bot's jabber account settings.
         | 
| 22 | 
            +
            Look at Examples section to see this configs.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            == ActiveRecord models
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            Implement your *ActiveRecord* models.
         | 
| 27 | 
            +
            You have to implement at least one model, for users.
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            == Prepare your database
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            == Your bot's class
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            === Rumpy::Bot module
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            You have to mix in your bot's class the <tt>Rumpy::Bot</tt> module:
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              include Rumpy::Bot
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            === Instance variables
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            +Rumpy+ uses next instance variables:
         | 
| 42 | 
            +
            <tt>@models_files</tt>    ::  Array of your models files.
         | 
| 43 | 
            +
            <tt>@config_path</tt>     ::  Path to directory, containing all ruby config files. Default is +config+.
         | 
| 44 | 
            +
            <tt>@main_model</tt>      ::  Symbol, that stands for main model. For example, if your main model is +User+, you have to set <tt>@main_model</tt> to <tt>:user</tt>. Default is <tt>:user</tt>.
         | 
| 45 | 
            +
            <tt>@pid_file</tt>        ::  Location of the file to which pid of detached process will be saved. Default is <tt>NameOfYourBotClass.downcase + '.pid'</tt>.
         | 
| 46 | 
            +
            <tt>@log_file</tt>        ::  Location of the logfile. Default is +STDERR+.
         | 
| 47 | 
            +
            <tt>@log_level</tt>       ::  Logging severity threshold. Possible values are the same the logger from standard library has. Default is <tt>Logger::INFO</tt>.
         | 
| 48 | 
            +
            <tt>@log_shift_age</tt>   ::  Number of old log files to keep, or frequency of rotation (_daily_, _weekly_ or _monthly_). Default is +0+.
         | 
| 49 | 
            +
            <tt>@log_shift_size</tt>  ::  Maximum logfile size. Default is +1048576+.
         | 
| 50 | 
            +
            <tt>@logger</tt>          ::  If you need more accuracy in configuring logger, simply create one. It have to be compatible with standard library's +logger+.
         | 
| 51 | 
            +
            <tt>@bot_name</tt>        ::  Name of the bot. Default is name of bot's class.
         | 
| 52 | 
            +
            <tt>@bot_version</tt>     ::  Optional version of the bot. Default is <tt>1.0.0</tt>.
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            === Instance methods
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            +Rumpy+ needs only three methods:
         | 
| 57 | 
            +
            <tt>backend_func() -> [[receiver, message]*]</tt> :: This *optional* method is running all the time in the loop. Returns array of pairs <tt>[receiver, message]</tt>.
         | 
| 58 | 
            +
            <tt>parser_func(msg) -> pars_result</tt>          :: This method parses any incoming message and returs results of parsing.
         | 
| 59 | 
            +
            <tt>do_func(usermodel, pars_results) -> msg</tt>  :: This method uses results from +parser_func+, doing some stuff with model of user, from whom the message was received. Returns the answer to this user.
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            _Hint_: empty answer will not be sent.
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            == Run bot
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            You can run your bot without detaching:
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              Rumpy.run YourBotClassName.new
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            Or with detaching:
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              bot = YourBotClassName.new
         | 
| 72 | 
            +
              #To start your bot:
         | 
| 73 | 
            +
              Rumpy.start bot
         | 
| 74 | 
            +
              #To stop it:
         | 
| 75 | 
            +
              Rumpy.stop bot
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            = Examples
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            Look at
         | 
| 80 | 
            +
            * {CuteBot}[https://github.com/MPogoda/CuteBot]
         | 
| 81 | 
            +
            * {yatodo}[https://github.com/MPogoda/yatodo]
         | 
| 82 | 
            +
            * {Noty}[https://github.com/Ximik/Noty]
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            = Contacts
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            Feel free to contact us about any questions related to +Rumpy+.
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            = License
         | 
| 60 89 |  | 
| 61 90 | 
             
            Rumpy is released under the MIT license.
         | 
    
        data/lib/rumpy.rb
    CHANGED
    
    | @@ -7,14 +7,13 @@ require 'logger' | |
| 7 7 |  | 
| 8 8 | 
             
            module Rumpy
         | 
| 9 9 |  | 
| 10 | 
            -
              #  | 
| 10 | 
            +
              # Start bot in new process,
         | 
| 11 11 | 
             
              # detach this process and save the pid of process in pid_file
         | 
| 12 | 
            -
              def self.start( | 
| 13 | 
            -
                bot           = botclass.new
         | 
| 12 | 
            +
              def self.start(bot)
         | 
| 14 13 | 
             
                pf            = pid_file bot
         | 
| 15 14 | 
             
                return false if File.exist? pf
         | 
| 16 15 |  | 
| 17 | 
            -
                bot.log_file  = "#{ | 
| 16 | 
            +
                bot.log_file  = "#{bot.class.to_s.downcase}.log"
         | 
| 18 17 |  | 
| 19 18 | 
             
                pid = fork do
         | 
| 20 19 | 
             
                  bot.start
         | 
| @@ -24,12 +23,12 @@ module Rumpy | |
| 24 23 | 
             
                  file.puts pid
         | 
| 25 24 | 
             
                end
         | 
| 26 25 | 
             
                true
         | 
| 27 | 
            -
              end # def self.start( | 
| 26 | 
            +
              end # def self.start(bot)
         | 
| 28 27 |  | 
| 29 28 | 
             
              # Determine the name of pid_file, read pid from this file
         | 
| 30 29 | 
             
              # and try to kill process with this pid
         | 
| 31 | 
            -
              def self.stop( | 
| 32 | 
            -
                pf = pid_file  | 
| 30 | 
            +
              def self.stop(bot)
         | 
| 31 | 
            +
                pf = pid_file bot
         | 
| 33 32 | 
             
                return false unless File.exist? pf
         | 
| 34 33 | 
             
                begin
         | 
| 35 34 | 
             
                  File.open(pf) do |file|
         | 
| @@ -39,11 +38,11 @@ module Rumpy | |
| 39 38 | 
             
                  File.unlink pf
         | 
| 40 39 | 
             
                end
         | 
| 41 40 | 
             
                true
         | 
| 42 | 
            -
              end # def self.stop( | 
| 41 | 
            +
              end # def self.stop(bot)
         | 
| 43 42 |  | 
| 44 | 
            -
              #  | 
| 45 | 
            -
              def self.run( | 
| 46 | 
            -
                 | 
| 43 | 
            +
              # Start bot without detaching
         | 
| 44 | 
            +
              def self.run(bot)
         | 
| 45 | 
            +
                bot.start
         | 
| 47 46 | 
             
              end
         | 
| 48 47 |  | 
| 49 48 | 
             
              # Determine the name of file where thid pid will stored to
         | 
| @@ -69,17 +68,20 @@ module Rumpy | |
| 69 68 | 
             
                  logger_init
         | 
| 70 69 |  | 
| 71 70 | 
             
                  init
         | 
| 71 | 
            +
             | 
| 72 72 | 
             
                  connect
         | 
| 73 | 
            -
                  prepare_users
         | 
| 74 73 |  | 
| 74 | 
            +
                  set_iq_callback
         | 
| 75 75 | 
             
                  set_subscription_callback
         | 
| 76 76 | 
             
                  set_message_callback
         | 
| 77 | 
            -
                  set_iq_callback
         | 
| 78 77 |  | 
| 79 78 | 
             
                  start_backend_thread
         | 
| 79 | 
            +
                  start_output_queue_thread
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  prepare_users
         | 
| 80 82 |  | 
| 81 83 | 
             
                  @logger.info 'Bot is going ONLINE'
         | 
| 82 | 
            -
                   | 
| 84 | 
            +
                  @output_queue.enq Jabber::Presence.new(nil, @status, @priority)
         | 
| 83 85 |  | 
| 84 86 | 
             
                  add_signal_trap
         | 
| 85 87 |  | 
| @@ -92,18 +94,21 @@ module Rumpy | |
| 92 94 | 
             
                private
         | 
| 93 95 |  | 
| 94 96 | 
             
                def logger_init
         | 
| 95 | 
            -
                  @ | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
                   | 
| 97 | 
            +
                  if @logger.nil? then
         | 
| 98 | 
            +
                    @log_file             ||= STDERR
         | 
| 99 | 
            +
                    @log_level            ||= Logger::INFO
         | 
| 100 | 
            +
                    @logger                 = Logger.new @log_file, @log_shift_age, @log_shift_size
         | 
| 101 | 
            +
                    @logger.level           = @log_level
         | 
| 102 | 
            +
                    @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
         | 
| 103 | 
            +
                  end
         | 
| 102 104 |  | 
| 103 105 | 
             
                  @logger.info 'starting bot'
         | 
| 104 106 | 
             
                end
         | 
| 105 107 |  | 
| 106 108 | 
             
                def init
         | 
| 109 | 
            +
                  @config_path ||= 'config'
         | 
| 110 | 
            +
                  @main_model  ||= :user
         | 
| 111 | 
            +
             | 
| 107 112 | 
             
                  @logger.debug 'initializing some variables'
         | 
| 108 113 |  | 
| 109 114 | 
             
                  xmppconfig  = YAML::load_file @config_path + '/xmpp.yml'
         | 
| @@ -119,13 +124,13 @@ module Rumpy | |
| 119 124 | 
             
                  @client     = Jabber::Client.new @jid
         | 
| 120 125 | 
             
                  Jabber::Version::SimpleResponder.new(@client, @bot_name || self.class.to_s, @bot_version || '1.0.0', RUBY_PLATFORM)
         | 
| 121 126 |  | 
| 122 | 
            -
                  if @ | 
| 127 | 
            +
                  if @models_files then
         | 
| 123 128 | 
             
                    dbconfig  = YAML::load_file @config_path + '/database.yml'
         | 
| 124 129 | 
             
                    @logger.info 'loaded database.yml'
         | 
| 125 130 | 
             
                    @logger.debug "database.yml: #{dbconfig.inspect}"
         | 
| 126 131 | 
             
                    ActiveRecord::Base.establish_connection dbconfig
         | 
| 127 132 | 
             
                    @logger.info 'database connection established'
         | 
| 128 | 
            -
                     | 
| 133 | 
            +
                    @models_files.each do |file|
         | 
| 129 134 | 
             
                      self.class.require file
         | 
| 130 135 | 
             
                      @logger.info "added models file '#{file}'"
         | 
| 131 136 | 
             
                    end
         | 
| @@ -133,13 +138,12 @@ module Rumpy | |
| 133 138 |  | 
| 134 139 | 
             
                  @main_model = Object.const_get @main_model.to_s.capitalize
         | 
| 135 140 | 
             
                  @logger.info "main model set to #{@main_model}"
         | 
| 136 | 
            -
                  def @main_model.find_by_jid(jid)
         | 
| 137 | 
            -
                    super jid.strip.to_s
         | 
| 138 | 
            -
                  end
         | 
| 139 141 |  | 
| 140 142 | 
             
                  @queues = Hash.new do |h, k|
         | 
| 141 143 | 
             
                    h[k]  = Queue.new
         | 
| 142 144 | 
             
                  end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  @output_queue = Queue.new
         | 
| 143 147 | 
             
                end # def init
         | 
| 144 148 |  | 
| 145 149 | 
             
                def connect
         | 
| @@ -153,35 +157,33 @@ module Rumpy | |
| 153 157 | 
             
                  @logger.info 'xmpp connection established'
         | 
| 154 158 | 
             
                end
         | 
| 155 159 |  | 
| 156 | 
            -
                def  | 
| 157 | 
            -
                  @ | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
                       | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
                       | 
| 160 | 
            +
                def set_iq_callback
         | 
| 161 | 
            +
                  @client.add_iq_callback do |iq|
         | 
| 162 | 
            +
                    @logger.debug "got iq #{iq}"
         | 
| 163 | 
            +
                    if iq.type == :get then # hack for pidgin (STOP USING IT)
         | 
| 164 | 
            +
                      response = iq.answer true
         | 
| 165 | 
            +
                      if iq.elements['time'] == "<time xmlns='urn:xmpp:time'/>" then
         | 
| 166 | 
            +
                        @logger.debug 'this is time request, okay'
         | 
| 167 | 
            +
                        response.set_type :result
         | 
| 168 | 
            +
                        tm = Time.now
         | 
| 169 | 
            +
                        response.elements['time'].add REXML::Element.new('tzo')
         | 
| 170 | 
            +
                        response.elements['time/tzo'].text = tm.xmlschema[-6..-1]
         | 
| 171 | 
            +
                        response.elements['time'].add REXML::Element.new('utc')
         | 
| 172 | 
            +
                        response.elements['time/utc'].text = tm.utc.xmlschema
         | 
| 173 | 
            +
                      else
         | 
| 174 | 
            +
                        response.set_type :error
         | 
| 175 | 
            +
                      end # if iq.elements['time']
         | 
| 176 | 
            +
                      @output_queue.enq response
         | 
| 173 177 | 
             
                    end
         | 
| 174 178 | 
             
                  end
         | 
| 175 | 
            -
             | 
| 176 | 
            -
                  @main_model.connection_pool.release_connection
         | 
| 177 | 
            -
                end # def prepare_users
         | 
| 179 | 
            +
                end # def set_iq_callback
         | 
| 178 180 |  | 
| 179 181 | 
             
                def set_subscription_callback
         | 
| 180 182 | 
             
                  @roster.add_subscription_request_callback do |item, presence|
         | 
| 181 183 | 
             
                    jid = presence.from
         | 
| 182 184 | 
             
                    @roster.accept_subscription jid
         | 
| 183 | 
            -
                     | 
| 184 | 
            -
                     | 
| 185 | 
            +
                    @output_queue.enq presence.answer.set_type :subscribe
         | 
| 186 | 
            +
                    @output_queue.enq Jabber::Message.new(jid, @lang['hello']).set_type :chat
         | 
| 185 187 |  | 
| 186 188 | 
             
                    @logger.info "#{jid} just subscribed"
         | 
| 187 189 | 
             
                  end
         | 
| @@ -199,10 +201,10 @@ module Rumpy | |
| 199 201 | 
             
                        start_user_thread user
         | 
| 200 202 |  | 
| 201 203 | 
             
                        @logger.info "added new user: #{user.jid}"
         | 
| 202 | 
            -
                         | 
| 204 | 
            +
                        @output_queue.enq Jabber::Message.new(item.jid, @lang['authorized']).set_type :chat
         | 
| 203 205 | 
             
                      end
         | 
| 204 206 | 
             
                    rescue ActiveRecord::StatementInvalid
         | 
| 205 | 
            -
                       | 
| 207 | 
            +
                      statement_invalid_error
         | 
| 206 208 | 
             
                      retry
         | 
| 207 209 | 
             
                    rescue ActiveRecord::ConnectionTimeoutError
         | 
| 208 210 | 
             
                      connection_timeout_error
         | 
| @@ -220,35 +222,14 @@ module Rumpy | |
| 220 222 | 
             
                        @logger.debug "got normal message #{msg}"
         | 
| 221 223 |  | 
| 222 224 | 
             
                        @queues[msg.from.strip.to_s].enq msg
         | 
| 223 | 
            -
                      else | 
| 225 | 
            +
                      else
         | 
| 224 226 | 
             
                        @logger.debug "user not in roster: #{msg.from}"
         | 
| 225 227 |  | 
| 226 | 
            -
                         | 
| 227 | 
            -
                      end | 
| 228 | 
            -
                    end # if msg.type != :error and msg.body and msg.from
         | 
| 229 | 
            -
                  end # @client.add_message_callback
         | 
| 230 | 
            -
                end # def set_message_callback
         | 
| 231 | 
            -
             | 
| 232 | 
            -
                def set_iq_callback
         | 
| 233 | 
            -
                  @client.add_iq_callback do |iq|
         | 
| 234 | 
            -
                    @logger.debug "got iq #{iq}"
         | 
| 235 | 
            -
                    if iq.type == :get then # hack for pidgin (STOP USING IT)
         | 
| 236 | 
            -
                      response = iq.answer true
         | 
| 237 | 
            -
                      if iq.elements['time'] == "<time xmlns='urn:xmpp:time'/>" then
         | 
| 238 | 
            -
                        @logger.debug 'this is time request, okay'
         | 
| 239 | 
            -
                        response.set_type :result
         | 
| 240 | 
            -
                        tm = Time.now
         | 
| 241 | 
            -
                        response.elements['time'].add REXML::Element.new('tzo')
         | 
| 242 | 
            -
                        response.elements['time/tzo'].text = tm.xmlschema[-6..-1]
         | 
| 243 | 
            -
                        response.elements['time'].add REXML::Element.new('utc')
         | 
| 244 | 
            -
                        response.elements['time/utc'].text = tm.utc.xmlschema
         | 
| 245 | 
            -
                      else
         | 
| 246 | 
            -
                        response.set_type :error
         | 
| 247 | 
            -
                      end # if iq.elements['time']
         | 
| 248 | 
            -
                      send_msg response
         | 
| 228 | 
            +
                        @output_queue.enq msg.answer.set_body @lang['stranger']
         | 
| 229 | 
            +
                      end
         | 
| 249 230 | 
             
                    end
         | 
| 250 231 | 
             
                  end
         | 
| 251 | 
            -
                end # def  | 
| 232 | 
            +
                end # def set_message_callback
         | 
| 252 233 |  | 
| 253 234 | 
             
                def start_backend_thread
         | 
| 254 235 | 
             
                  Thread.new do
         | 
| @@ -256,11 +237,11 @@ module Rumpy | |
| 256 237 | 
             
                      loop do
         | 
| 257 238 | 
             
                        backend_func().each do |result|
         | 
| 258 239 | 
             
                          message = Jabber::Message.new(*result).set_type :chat
         | 
| 259 | 
            -
                           | 
| 240 | 
            +
                          @output_queue.enq message if message.body and message.to
         | 
| 260 241 | 
             
                        end
         | 
| 261 242 | 
             
                      end
         | 
| 262 243 | 
             
                    rescue ActiveRecord::StatementInvalid
         | 
| 263 | 
            -
                       | 
| 244 | 
            +
                      statement_invalid_error
         | 
| 264 245 | 
             
                      retry
         | 
| 265 246 | 
             
                    rescue ActiveRecord::ConnectionTimeoutError
         | 
| 266 247 | 
             
                      connection_timeout_error
         | 
| @@ -271,17 +252,34 @@ module Rumpy | |
| 271 252 | 
             
                  end if self.respond_to? :backend_func
         | 
| 272 253 | 
             
                end # def start_backend_thread
         | 
| 273 254 |  | 
| 255 | 
            +
                def start_output_queue_thread
         | 
| 256 | 
            +
                  Thread.new do
         | 
| 257 | 
            +
                    @logger.info "Output queue initialized"
         | 
| 258 | 
            +
                    until (msg = @output_queue.deq) == :halt do
         | 
| 259 | 
            +
                      if msg.nil? then
         | 
| 260 | 
            +
                        @logger.debug "got nil message. wtf?"
         | 
| 261 | 
            +
                      else
         | 
| 262 | 
            +
                        @logger.debug "sending message #{msg}"
         | 
| 263 | 
            +
                        @client.send msg
         | 
| 264 | 
            +
                      end
         | 
| 265 | 
            +
                    end
         | 
| 266 | 
            +
                    @logger.info "Output queue destroyed"
         | 
| 267 | 
            +
                  end
         | 
| 268 | 
            +
                end # def start_output_queue_thread
         | 
| 269 | 
            +
             | 
| 274 270 | 
             
                def add_signal_trap
         | 
| 275 271 | 
             
                  Signal.trap :TERM do |signo| # soft stop
         | 
| 276 272 | 
             
                    @logger.info 'Bot is unavailable'
         | 
| 277 | 
            -
                     | 
| 273 | 
            +
                    @output_queue.enq Jabber::Presence.new.set_type :unavailable
         | 
| 278 274 |  | 
| 279 275 | 
             
                    @queues.each do |user, queue|
         | 
| 280 276 | 
             
                      queue.enq :halt
         | 
| 281 277 | 
             
                    end
         | 
| 282 | 
            -
                    until @queues.empty?
         | 
| 283 | 
            -
             | 
| 284 | 
            -
                     | 
| 278 | 
            +
                    sleep 1 until @queues.empty?
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                    @output_queue.enq :halt
         | 
| 281 | 
            +
                    sleep 1 until @output_queue.empty?
         | 
| 282 | 
            +
             | 
| 285 283 | 
             
                    @client.close
         | 
| 286 284 |  | 
| 287 285 | 
             
                    @logger.info 'terminating'
         | 
| @@ -290,28 +288,41 @@ module Rumpy | |
| 290 288 | 
             
                  end
         | 
| 291 289 | 
             
                end
         | 
| 292 290 |  | 
| 291 | 
            +
                def prepare_users
         | 
| 292 | 
            +
                  @logger.debug 'clear wrong users'
         | 
| 293 | 
            +
             | 
| 294 | 
            +
                  @roster.items.each do |jid, item|
         | 
| 295 | 
            +
                    user = @main_model.find_by_jid jid.strip.to_s
         | 
| 296 | 
            +
                    if user.nil? or item.subscription != :both then
         | 
| 297 | 
            +
                      @logger.info "deleting from roster user with jid #{jid}"
         | 
| 298 | 
            +
                      item.remove
         | 
| 299 | 
            +
                    end
         | 
| 300 | 
            +
                  end
         | 
| 301 | 
            +
                  @main_model.find_each do |user|
         | 
| 302 | 
            +
                    items = @roster.find user.jid
         | 
| 303 | 
            +
                    if items.empty? then
         | 
| 304 | 
            +
                      @logger.info "deleting from database user with jid #{user.jid}"
         | 
| 305 | 
            +
                      user.destroy
         | 
| 306 | 
            +
                    else
         | 
| 307 | 
            +
                      start_user_thread user
         | 
| 308 | 
            +
                    end
         | 
| 309 | 
            +
                  end
         | 
| 310 | 
            +
             | 
| 311 | 
            +
                  @main_model.connection_pool.release_connection
         | 
| 312 | 
            +
                end # def prepare_users
         | 
| 313 | 
            +
             | 
| 293 314 | 
             
                def start_user_thread(user)
         | 
| 294 315 | 
             
                  Thread.new(user) do |user|
         | 
| 316 | 
            +
                    @logger.debug "thread for user #{user.jid} started"
         | 
| 295 317 |  | 
| 296 | 
            -
                     | 
| 297 | 
            -
                      msg = @queues[user.jid].deq
         | 
| 298 | 
            -
             | 
| 318 | 
            +
                    until (msg = @queues[user.jid].deq).kind_of? Symbol do
         | 
| 299 319 | 
             
                      begin
         | 
| 300 | 
            -
                        if msg.kind_of? Symbol then # :unsubscribe or :halt
         | 
| 301 | 
            -
                          if msg == :unsubscribe
         | 
| 302 | 
            -
                            @logger.info "removing user #{user.jid}"
         | 
| 303 | 
            -
                            user.destroy
         | 
| 304 | 
            -
                          end
         | 
| 305 | 
            -
                          @queues.delete user.jid
         | 
| 306 | 
            -
                          break
         | 
| 307 | 
            -
                        end
         | 
| 308 | 
            -
             | 
| 309 320 | 
             
                        pars_results = parser_func msg.body
         | 
| 310 321 | 
             
                        @logger.debug "parsed message: #{pars_results.inspect}"
         | 
| 311 | 
            -
                         | 
| 312 | 
            -
                         | 
| 322 | 
            +
                        answer = do_func user, pars_results
         | 
| 323 | 
            +
                        @output_queue.enq msg.answer.set_body answer unless answer.nil? or answer.empty?
         | 
| 313 324 | 
             
                      rescue ActiveRecord::StatementInvalid
         | 
| 314 | 
            -
                         | 
| 325 | 
            +
                        statement_invalid_error
         | 
| 315 326 | 
             
                        retry
         | 
| 316 327 | 
             
                      rescue ActiveRecord::ConnectionTimeoutError
         | 
| 317 328 | 
             
                        connection_timeout_error
         | 
| @@ -321,18 +332,19 @@ module Rumpy | |
| 321 332 | 
             
                      end # begin
         | 
| 322 333 |  | 
| 323 334 | 
             
                      @main_model.connection_pool.release_connection
         | 
| 324 | 
            -
                    end #  | 
| 325 | 
            -
                    Thread.current.join
         | 
| 326 | 
            -
                  end # Thread.new do
         | 
| 327 | 
            -
                end # def start_user_thread(queue)
         | 
| 335 | 
            +
                    end # until (msg = @queues[user.jid].deq).kind_of? Symbol do
         | 
| 328 336 |  | 
| 329 | 
            -
             | 
| 330 | 
            -
             | 
| 331 | 
            -
             | 
| 332 | 
            -
             | 
| 333 | 
            -
             | 
| 337 | 
            +
                    if msg == :unsubscribe
         | 
| 338 | 
            +
                      @logger.info "removing user #{user.jid}"
         | 
| 339 | 
            +
                      user.destroy
         | 
| 340 | 
            +
                    end
         | 
| 341 | 
            +
             | 
| 342 | 
            +
                    @queues.delete user.jid
         | 
| 343 | 
            +
             | 
| 344 | 
            +
                  end # Thread.new do
         | 
| 345 | 
            +
                end # def start_user_thread(user)
         | 
| 334 346 |  | 
| 335 | 
            -
                def  | 
| 347 | 
            +
                def statement_invalid_error
         | 
| 336 348 | 
             
                  @logger.warn 'Statement Invalid catched'
         | 
| 337 349 | 
             
                  @logger.info 'Reconnecting to database'
         | 
| 338 350 | 
             
                  @main_model.connection.reconnect!
         | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: rumpy
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 29
         | 
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 8 | 
             
              - 9
         | 
| 9 | 
            -
              -  | 
| 10 | 
            -
              version: 0.9. | 
| 9 | 
            +
              - 19
         | 
| 10 | 
            +
              version: 0.9.19
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Tsokurov A.G.
         | 
| @@ -16,7 +16,7 @@ autorequire: | |
| 16 16 | 
             
            bindir: bin
         | 
| 17 17 | 
             
            cert_chain: []
         | 
| 18 18 |  | 
| 19 | 
            -
            date: 2011-08- | 
| 19 | 
            +
            date: 2011-08-20 00:00:00 +03:00
         | 
| 20 20 | 
             
            default_executable: 
         | 
| 21 21 | 
             
            dependencies: 
         | 
| 22 22 | 
             
            - !ruby/object:Gem::Dependency 
         |