botolo 0.32.9 → 0.50.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cbeb05fdb3cf739092a995a69966641a8f22e7b7
4
- data.tar.gz: 34c717174161db5935f779b1052688f3e88cc811
3
+ metadata.gz: 5db849cbb8017808accaae72cc3f6b430fcf963f
4
+ data.tar.gz: f00801595c7363ad64c12ac6cf1311b0b42a846c
5
5
  SHA512:
6
- metadata.gz: 08396913b0678a35bafaa2ab52c12721523c509289f93da373648a3f8522b2417757ef7b80b2770ad7644c8abab3f5f2f173cd38e39416f6a20833f2dfcd7c71
7
- data.tar.gz: 02941872a2b6f03cbfa002877862e397a4004740030bcb95fbaf278733264776d5009e320603f2e5c45e451711f285d68a031c3f34f40e747b677a67eb21ad21
6
+ metadata.gz: f9a3246e555a4895cce738cc2260f68945f1f8c3579ad5eb88bdd972ff1672673222a57dab80001fdede898b9ed5be8990fa4ea0ec48b3a709b7f8aafdcbacb7
7
+ data.tar.gz: 45a383398b60148e2dcf444c94ed47fcae0acfcab719cb51550b37dd691ac8283fc71437b76e02d9a24383fc5cbe89f308974a794d5c61dd74083bb8319eb5d6
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ botolo
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.1.3
data/README.md CHANGED
@@ -39,6 +39,7 @@ bot:
39
39
  email: paolo@codesake.com
40
40
  # This overrides any behaviour file passed as argument
41
41
  behaviour: dummy-bot.rb
42
+ logfile: dummy-bot.log
42
43
 
43
44
  twitter:
44
45
  enabled: no
@@ -110,10 +111,49 @@ botolo:9: warning: already initialized constant OpenSSL::SSL::VERIFY_PEER
110
111
  Custom written behaviour can use the global variable $logger to use botolo logging
111
112
  facilities and having the stdout/stderr prints more consistent.
112
113
 
114
+ The same ruby class can have some social integration adding twitter support in
115
+ its behaviour file.
116
+
117
+ Since botolo version 0.50, more twitter accounts are supported and
118
+ Botolo::API::Twitter are introduced to provide basic services to your bots.
119
+
120
+ ```
121
+ verbose: true
122
+
123
+ bot:
124
+ name: dummy-bot
125
+ version: 1.0
126
+ email: paolo@codesake.com
127
+ behaviour: dummy-bot.rb
128
+
129
+ twitter:
130
+ enabled: yes
131
+ accounts:
132
+ - { name: first, consumer_key: "AAAAAAAAAAAAAAAAAAAAAAAAA", consumer_secret: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", oauth_token: "999999999-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", oauth_token_secret: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}
133
+ - { name: second, consumer_key: "AAAAAAAAAAAAAAAAAAAAAAAAA", consumer_secret: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", oauth_token: "999999999-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", oauth_token_secret: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}
134
+ - { name: third, consumer_key: "AAAAAAAAAAAAAAAAAAAAAAAAA", consumer_secret: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", oauth_token: "999999999-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", oauth_token_secret: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}
135
+
136
+ task:
137
+ - { schedule: every 5 s, action: say_hello }
138
+ - { schedule: every 3 s, action: say_foo }
139
+ - { schedule: every 1 h, action: tweet_hello }
140
+ ```
141
+
142
+ The tweet\_hello routine is very simple:
143
+
144
+ ```
145
+ def tweet_hello
146
+ return "" if $twitter_api.nil?
147
+ $twitter_api.tweet("hello")
148
+ end
149
+ ```
150
+
151
+ The ```$twitter_api``` ojeect is something provided by the engine, so it's very
152
+ easy for bot writers.
153
+
113
154
  ## Missing features
114
155
 
115
- A back channels for threads to communicate with the engine about action
116
- status.
156
+ Other social network integration, mainly facebook.
117
157
 
118
158
  ## Contributing
119
159
 
data/bin/botolo CHANGED
@@ -3,6 +3,13 @@
3
3
  require 'botolo'
4
4
  require 'openssl'
5
5
  require 'codesake-commons'
6
+ require 'getoptlong'
7
+
8
+ opts = GetoptLong.new(
9
+ [ "--debug", "-D", GetoptLong::NO_ARGUMENT],
10
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT],
11
+ [ "--version", "-v", GetoptLong::NO_ARGUMENT ]
12
+ )
6
13
 
7
14
  DEFAULT_BEHAVIOUR = "./lib/botolo/bot/behaviour.rb"
8
15
  BOTOLO_PID = File.join(".", "botolo.pid")
@@ -10,8 +17,29 @@ BOTOLO_PID = File.join(".", "botolo.pid")
10
17
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
11
18
 
12
19
  $logger = Codesake::Commons::Logging.instance
13
- $logger.filename="./codesake-bot.log"
14
- trap("INT") { @bot.stop; $logger.bye; Kernel.exit(0); }
20
+ trap("INT") { @bot.stop; $logger.bye; File.delete(BOTOLO_PID); Kernel.exit(0); }
21
+
22
+ opts.quiet=true
23
+ debug = false
24
+
25
+ begin
26
+ opts.each do |opt, val|
27
+ case opt
28
+ when '--version'
29
+ puts "#{Botolo::VERSION}"
30
+ Kernel.exit(0)
31
+ when '--help'
32
+ puts "I'll put an help here... promise"
33
+ Kernel.exit(0)
34
+ when '--debug'
35
+ debug = true
36
+ end
37
+ end
38
+ rescue GetoptLong::InvalidOption => e
39
+ $logger.helo "botolo", Botolo::VERSION, BOTOLO_PID
40
+ $logger.err e.message
41
+ Kernel.exit(-1)
42
+ end
15
43
 
16
44
  behaviour_file = DEFAULT_BEHAVIOUR
17
45
  config_file = nil
@@ -22,10 +50,15 @@ $logger.die "usage: botolo bot_configuration_file" if config_file.nil?
22
50
  $logger.helo "botolo", Botolo::VERSION, BOTOLO_PID
23
51
 
24
52
  @bot = Botolo::Bot::Engine.new({:config=>config_file})
25
- $logger.log "#{@bot.name} is online" if @bot.online?
53
+ $logger.log "#{@bot.name} is online" if @bot.online?
26
54
  $logger.log "#{@bot.name} is offline" unless @bot.online?
27
- @bot.run if @bot.online?
28
- # Process.daemon(true, true)
55
+
56
+ if debug
57
+ $logger.debug "forcing #{@bot.name} run"
58
+ @bot.run
59
+ else
60
+ @bot.run if @bot.online?
61
+ end
29
62
  @bot.infinite_loop
30
63
 
31
64
 
data/botolo.gemspec CHANGED
@@ -23,6 +23,6 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
  spec.add_development_dependency "rake"
26
- spec.add_dependency "twitter"
27
- spec.add_dependency "codesake-commons"
26
+ spec.add_dependency "twitter", "~> 5.11.0"
27
+ spec.add_dependency "codesake-commons", "~> 1.0.0"
28
28
  end
@@ -0,0 +1,15 @@
1
+ verbose: true
2
+
3
+ bot:
4
+ name: dummy-bot
5
+ version: 1.0
6
+ email: paolo@codesake.com
7
+ logfile: dummy_log.log
8
+ behaviour: dummy_bot.rb
9
+
10
+ twitter:
11
+ enabled: no
12
+
13
+ task:
14
+ - { schedule: every 5 s, action: say_hello }
15
+ - { schedule: every 3 s, action: say_foo }
@@ -0,0 +1,22 @@
1
+ module Botolo
2
+ module Bot
3
+ class Behaviour
4
+ def initialize(options={})
5
+ end
6
+
7
+ def say_hello
8
+ puts "hello"
9
+ end
10
+
11
+ def say_foo
12
+ puts "foo"
13
+ end
14
+
15
+ def tweet_hello
16
+ return "" if $twitter_api.nil?
17
+ $twitter_api.tweet("hello")
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,19 @@
1
+ verbose: true
2
+
3
+ bot:
4
+ name: dummy-bot
5
+ version: 1.0
6
+ email: paolo@codesake.com
7
+ behaviour: dummy_bot.rb
8
+
9
+ twitter:
10
+ enabled: yes
11
+ accounts:
12
+ - {name: first, consumer_key: "AAAAAAAAAAAAAAAAAAAAAAAAA", consumer_secret: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", oauth_token: "999999999-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", oauth_token_secret: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}
13
+ - {name: second, consumer_key: "AAAAAAAAAAAAAAAAAAAAAAAAA", consumer_secret: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", oauth_token: "999999999-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", oauth_token_secret: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}
14
+ - {name: third, consumer_key: "AAAAAAAAAAAAAAAAAAAAAAAAA", consumer_secret: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", oauth_token: "999999999-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", oauth_token_secret: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}
15
+
16
+ task:
17
+ - { schedule: every 5 s, action: say_hello }
18
+ - { schedule: every 3 s, action: say_foo }
19
+ - { schedule: every 1 h, action: tweet_hello }
data/lib/botolo.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require "botolo/version"
2
+ require "botolo/api/blog"
3
+ require "botolo/api/tweet"
2
4
  require "botolo/bot/engine"
@@ -0,0 +1,57 @@
1
+ require 'rss'
2
+
3
+ module Botolo
4
+ module API
5
+ class Blog
6
+
7
+ def initialize(options={})
8
+ @url = options[:url]
9
+ @tweet = options[:tweet_api]
10
+ end
11
+
12
+ def refresh_rss
13
+ rss = nil
14
+
15
+ open("#{@url}/feed.xml") do |http|
16
+ response = http.read
17
+ rss = RSS::Parser.parse(response, false)
18
+ end
19
+ @feed = []
20
+ rss.items.each_with_index do |item, i|
21
+ @feed << {:title=>item.title.content, :link=>item.link.href}
22
+ end
23
+ $logger.log "#{@feed.size} elements loaded from feed"
24
+ end
25
+
26
+ def tweet_random_posts(limit = 3, hashtags="")
27
+ return nil if @feed.nil? || @feed.size == 0
28
+ (0..limit-1).each do |l|
29
+ post = @feed[SecureRandom.random_number(@feed.size)]
30
+ m = "\"#{post[:title]}\" (#{post[:link]}) #{hashtags}"
31
+ $logger.debug "#{m} - #{m.length}"
32
+ begin
33
+ @tweet.tweet(m)
34
+ $logger.debug "tweet sent!"
35
+ rescue => e
36
+ $logger.err("error tweeting #{m}: #{e.message}")
37
+ end
38
+ sleep(10)
39
+
40
+ end
41
+ end
42
+
43
+ def promote_latest(hashtags="")
44
+ return nil if @feed.nil? || @feed.size == 0
45
+ post = @feed[0]
46
+ m = "\"#{post[:title]}\" (#{post[:link]}) #blog #sicurezza #informatica."
47
+ $logger.debug "#{m} - #{m.length}"
48
+ begin
49
+ @tweet.tweet(m)
50
+ rescue => e
51
+ $logger.err("error tweeting #{m}: #{e.message}")
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,77 @@
1
+ require 'twitter'
2
+ require 'singleton'
3
+
4
+ module Botolo
5
+ module API
6
+ class Tweet
7
+
8
+ # twitters is a twitter client array read from configuration file and
9
+ # used to access the social network for a given account.
10
+ attr_reader :twitters
11
+ include Singleton
12
+
13
+ def authenticate(config)
14
+ @twitters = []
15
+ config['accounts'].each do |account|
16
+ a=Hash.new
17
+ a[:name] = account['name']
18
+ begin
19
+ a[:client] = Twitter::REST::Client.new do |config|
20
+ config.consumer_key = account['consumer_key']
21
+ config.consumer_secret = account['consumer_secret']
22
+
23
+ config.access_token = account['access_token'] unless account['access_token'].nil?
24
+ config.access_token_secret = account['access_token_secret'] unless account['access_token_secret'].nil?
25
+ end
26
+ rescue Exception => e
27
+ $logger.err e.message
28
+ end
29
+
30
+ @twitters << a
31
+ end
32
+
33
+ @twitters
34
+ end
35
+
36
+ def tweet(name=nil, msg)
37
+ return nil if msg.empty?
38
+ @twitters.each do |t|
39
+ t[:client].update(msg) if (name.nil? or (!name.nil? and name == t[:name]))
40
+ end
41
+ return msg
42
+ end
43
+
44
+ def retweet(name=nil, msg)
45
+ return nil if msg.empty?
46
+ @twitters.each do |t|
47
+ t[:client].retweet(msg) if (name.nil? or (!name.nil? and name == t[:name]))
48
+ end
49
+ return msg
50
+ end
51
+
52
+ def find_and_retweet_topic(limit = 5, topic)
53
+ list = []
54
+ @twitters.each do |tt|
55
+ list << tt[:client].search("#appsec").to_a
56
+ end
57
+
58
+ unless list.nil?
59
+ (0..limit-1).each do |l|
60
+ t = list[SecureRandom.random_number(list.count)]
61
+ $logger.debug "retwitting #{t["from_user"]}: #{t["text"]}"
62
+ begin
63
+ @twitters.each do |t|
64
+ t[:client].retweet(msg) if (name.nil? or (!name.nil? and name == t[:name]))
65
+ end
66
+ rescue => e
67
+ $logger.err("error tweeting #{t["text"]}: #{e.message}")
68
+ end
69
+ sleep(15)
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+ end
76
+ end
77
+ end
@@ -1,4 +1,3 @@
1
- require 'twitter'
2
1
  require 'yaml'
3
2
 
4
3
  module Botolo
@@ -9,26 +8,36 @@ module Botolo
9
8
  @start_time = Time.now
10
9
  @online = false
11
10
  @config = read_conf(options[:config])
12
- $twitter_client = nil
13
- authenticate if @config['twitter']['enabled']
11
+ $twitter_api = nil
12
+
13
+ behaviour_path = File.dirname(options[:config])
14
+
15
+ if @config['twitter']['enabled']
16
+ $twitter_api = Botolo::API::Tweet.instance
17
+ $twitter_api.authenticate(@config['twitter'])
18
+ end
14
19
 
15
20
  @tasks = @config['task']
16
21
  @task_pids = []
17
22
 
18
- behaviour = File.join(".", @config['bot']['behaviour']) unless @config['bot']['behaviour'].nil?
23
+ behaviour = File.join(behaviour_path, @config['bot']['behaviour']) unless @config['bot']['behaviour'].nil?
19
24
 
20
25
  $logger.helo name, version
26
+ $logger.filename = File.join(".", logfile) unless logfile.nil?
27
+
21
28
  $logger.log "#{@tasks.size} tasks loaded"
22
29
 
23
30
  begin
24
31
  load behaviour
25
32
  $logger.log "using #{behaviour} as bot behaviour"
26
33
  @behaviour = Botolo::Bot::Behaviour.new(@config)
34
+ @start_time = Time.now
27
35
  rescue => e
28
36
  $logger.err(e.message)
29
37
  require 'botolo/bot/behaviour'
30
38
  $logger.log "reverting to default dummy behaviour"
31
39
  @behaviour = Botolo::Bot::Behaviour.new(@config)
40
+ @start_time = Time.now
32
41
  end
33
42
  end
34
43
 
@@ -57,11 +66,25 @@ module Botolo
57
66
 
58
67
  def infinite_loop
59
68
  loop do
60
- sleep(3600) # => 1 d
61
- $logger.log " --- mark --- "
69
+ sleep(3600) # => 1 h
70
+ $logger.log " --- mark --- (bot: #{@behaviour.name}, uptime: #{uptime})"
62
71
  end
63
72
  end
64
73
 
74
+ def uptime
75
+ seconds_diff = (Time.now - @start_time).to_i.abs
76
+
77
+ days = seconds_diff / 86400
78
+ seconds_diff -= days * 86400
79
+
80
+ hours = seconds_diff / 3600
81
+ seconds_diff -= hours * 3600
82
+
83
+ minutes = seconds_diff / 60
84
+
85
+ "#{days.to_s} days, #{hours.to_s.rjust(2, '0')}:#{minutes.to_s.rjust(2, '0')}"
86
+ end
87
+
65
88
  def start_task(name, sleep)
66
89
  while true
67
90
  begin
@@ -86,24 +109,14 @@ module Botolo
86
109
  true
87
110
  end
88
111
 
89
- def authenticate
90
- begin
91
- $twitter_client = Twitter::REST::Client.new do |config|
92
- config.consumer_key = @config['twitter']['consumer_key']
93
- config.consumer_secret = @config['twitter']['consumer_secret']
94
- config.oauth_token = @config['twitter']['oauth_token']
95
- config.oauth_token_secret = @config['twitter']['oauth_token_secret']
96
- end
97
- @online = true
98
- rescue Exception => e
99
- $logger.err e.message
100
- end
101
- end
102
-
103
112
  def online?
104
113
  @online
105
114
  end
106
115
 
116
+ def logfile
117
+ return @config['bot']['logfile']
118
+ end
119
+
107
120
  def name
108
121
  return @config['bot']['name']
109
122
  end
@@ -1,3 +1,3 @@
1
1
  module Botolo
2
- VERSION = "0.32.9"
2
+ VERSION = "0.50.0"
3
3
  end
metadata CHANGED
@@ -1,71 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: botolo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.32.9
4
+ version: 0.50.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paolo Perego
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-30 00:00:00.000000000 Z
11
+ date: 2014-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: twitter
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 5.11.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 5.11.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: codesake-commons
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 1.0.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 1.0.0
69
69
  description: botolo is a bot engine written in ruby
70
70
  email:
71
71
  - thesp0nge@gmail.com
@@ -74,14 +74,21 @@ executables:
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
- - .gitignore
77
+ - ".gitignore"
78
+ - ".ruby-gemset"
79
+ - ".ruby-version"
78
80
  - Gemfile
79
81
  - LICENSE.txt
80
82
  - README.md
81
83
  - Rakefile
82
84
  - bin/botolo
83
85
  - botolo.gemspec
86
+ - examples/config.yaml
87
+ - examples/dummy_bot.rb
88
+ - examples/dummy_multiple_twitters.yaml
84
89
  - lib/botolo.rb
90
+ - lib/botolo/api/blog.rb
91
+ - lib/botolo/api/tweet.rb
85
92
  - lib/botolo/bot/behaviour.rb
86
93
  - lib/botolo/bot/engine.rb
87
94
  - lib/botolo/version.rb
@@ -95,17 +102,17 @@ require_paths:
95
102
  - lib
96
103
  required_ruby_version: !ruby/object:Gem::Requirement
97
104
  requirements:
98
- - - '>='
105
+ - - ">="
99
106
  - !ruby/object:Gem::Version
100
107
  version: '0'
101
108
  required_rubygems_version: !ruby/object:Gem::Requirement
102
109
  requirements:
103
- - - '>='
110
+ - - ">="
104
111
  - !ruby/object:Gem::Version
105
112
  version: '0'
106
113
  requirements: []
107
114
  rubyforge_project:
108
- rubygems_version: 2.1.11
115
+ rubygems_version: 2.2.2
109
116
  signing_key:
110
117
  specification_version: 4
111
118
  summary: botolo is a bot engine written in ruby. With botolo you can focus on writing