rbitter 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +21 -21
  3. data/.rspec +2 -2
  4. data/.travis.yml +15 -15
  5. data/Gemfile +12 -12
  6. data/LICENSE.txt +22 -22
  7. data/Rakefile +8 -8
  8. data/XMLRPC.md +19 -19
  9. data/bin/rbitter +20 -20
  10. data/lib/rbitter/arcserver.rb +130 -126
  11. data/lib/rbitter/console.rb +93 -93
  12. data/lib/rbitter/default/config_json.rb +37 -38
  13. data/lib/rbitter/dlthread.rb +62 -65
  14. data/lib/rbitter/env.rb +62 -62
  15. data/lib/rbitter/libtwitter_connection_override.rb +45 -45
  16. data/lib/rbitter/records.rb +121 -121
  17. data/lib/rbitter/records_migrate/20150327_add_index.rb +11 -11
  18. data/lib/rbitter/records_migrate/20150504_add_replyto_column.rb +11 -11
  19. data/lib/rbitter/streaming.rb +104 -104
  20. data/lib/rbitter/version.rb +20 -20
  21. data/lib/rbitter/xmlrpc.rb +3 -3
  22. data/lib/rbitter/xmlrpcd/base.rb +24 -24
  23. data/lib/rbitter/xmlrpcd/rpchandles.rb +11 -11
  24. data/lib/rbitter/xmlrpcd/xmlrpc_auth_server.rb +82 -82
  25. data/lib/rbitter/xmlrpcd/xmlrpcd.rb +69 -69
  26. data/lib/rbitter.rb +86 -86
  27. data/rbitter.gemspec +46 -42
  28. data/spec/config/default.json +32 -32
  29. data/spec/rbitter/arcserver_spec.rb +30 -30
  30. data/spec/rbitter/console_spec.rb +9 -9
  31. data/spec/rbitter/default/config_json_spec.rb +3 -3
  32. data/spec/rbitter/dlthread_spec.rb +8 -13
  33. data/spec/rbitter/env_spec.rb +62 -62
  34. data/spec/rbitter/libtwitter_connection_override_spec.rb +8 -8
  35. data/spec/rbitter/records_spec.rb +13 -13
  36. data/spec/rbitter/streaming_spec.rb +9 -9
  37. data/spec/rbitter/version_spec.rb +8 -8
  38. data/spec/rbitter/xmlrpc_spec.rb +8 -8
  39. data/spec/rbitter/xmlrpcd/base_spec.rb +29 -29
  40. data/spec/rbitter/xmlrpcd/rpchandles_spec.rb +10 -10
  41. data/spec/rbitter/xmlrpcd/xmlrpc_auth_server_spec.rb +8 -8
  42. data/spec/rbitter/xmlrpcd/xmlrpcd_spec.rb +9 -9
  43. data/spec/rbitter_spec.rb +42 -42
  44. data/spec/spec_helper.rb +39 -39
  45. metadata +29 -56
@@ -1,121 +1,121 @@
1
- # encoding: utf-8
2
-
3
- require "active_record"
4
- require "date"
5
-
6
- module Rbitter
7
- class Record < ActiveRecord::Base
8
- end
9
- end
10
-
11
- module ARSupport
12
- SCHEME_VERSION = 20150504
13
- SCHEME = {
14
- :marker => :integer, # 0 normal, 1 begin 2 halt
15
- :marker_msg => :string,
16
- :userid => :integer,
17
- :username => :string,
18
- :tweetid => :integer,
19
- :replyto => :integer,
20
- :tweet => :text, # with url unpacked
21
- :date => :datetime,
22
- :rt_count => :integer,
23
- :fav_count => :integer
24
- }
25
-
26
- module_function
27
- def prepared?
28
- ActiveRecord::Base.connection.table_exists?(:records)
29
- end
30
-
31
- def connect_database
32
- if Rbitter['activerecord'] == 'sqlite3'
33
- warn "Warning: If you enable XMLRPC access, using sqlite is not recommended."
34
- warn "Warning: Random crash can happen because of concurrency."
35
-
36
- if RUBY_PLATFORM == 'java'
37
- require "jdbc/sqlite3"
38
- Jdbc::SQLite3.load_driver
39
- ActiveRecord::Base.establish_connection(
40
- adapter: 'jdbcsqlite3',
41
- database: Rbitter['sqlite3']['dbfile'],
42
- timeout: 10000) # Long timeout for slow computer
43
- else
44
- ActiveRecord::Base.establish_connection(
45
- adapter: 'sqlite3',
46
- database: Rbitter['sqlite3']['dbfile'],
47
- timeout: 10000) # Long timeout for slow computer
48
- end
49
- elsif Rbitter['activerecord'] == 'mysql2'
50
- Jdbc::MySQL.load_driver if RUBY_PLATFORM == 'java'
51
-
52
- ActiveRecord::Base.establish_connection(
53
- adapter: (RUBY_PLATFORM == 'java' ? 'jdbcmysql' : 'mysql2'),
54
- host: Rbitter['mysql2']['host'],
55
- port: Rbitter['mysql2']['port'],
56
- database: Rbitter['mysql2']['dbname'],
57
- username: Rbitter['mysql2']['username'],
58
- password: Rbitter['mysql2']['password'],
59
- encoding: "utf8mb4",
60
- collation: "utf8mb4_unicode_ci")
61
- else
62
- raise RuntimeException.new("Unknown configuration value. 'activerecord' value should be sqlite3 or mysql2.")
63
- end
64
- end
65
-
66
- def update_database_scheme
67
- current_version = ActiveRecord::Migrator.current_version
68
- if current_version < SCHEME_VERSION
69
- warn "[records] Your ActiveRecord scheme is outdated."
70
- warn "[records] Migrate... #{current_version} => #{SCHEME_VERSION}"
71
- ActiveRecord::Migrator.migrate(File.expand_path("../records_migrate", __FILE__), SCHEME_VERSION)
72
- end
73
- end
74
-
75
- def prepare option_string=""
76
- ActiveRecord::Schema.define(version: SCHEME_VERSION) {
77
- # MySQL specific option_string:
78
- # utf8mb4 -> supporting UTF-8 4-byte characters (i.e. Emoji)
79
- create_table(:records, { :options => option_string }) do |t|
80
- SCHEME.each_key { |column|
81
- case SCHEME[column]
82
- when :string
83
- t.string column
84
- when :integer
85
- t.integer column, :limit => 8
86
- when :datetime
87
- t.datetime column
88
- when :text
89
- t.text column
90
- else
91
- puts "Unexpected column type '#{SCHEME[column]}' of #{column}"
92
- end
93
- }
94
- end
95
-
96
- add_index :records, :tweetid
97
- }
98
- end
99
-
100
- def any_to_datestring(obj)
101
- if obj.is_a?(String)
102
- # try to parse it
103
- DateTime.parse(obj).strftime("%Y-%m-%d %H:%M:%S")
104
- elsif obj.is_a?(DateTime) or obj.is_a?(Time)
105
- obj.strftime("%Y-%m-%d %H:%M:%S")
106
- else
107
- raise ArgumentError.new("Can\'t automatically extract DateTime info")
108
- end
109
- end
110
-
111
- def export_to_csv(csvfile)
112
- open(csvfile, 'w') { |f|
113
- f.write("marker,marker_msg,userid,username,tweetid,replyto,tweet,date,rt_count,fav_count")
114
- f.write("\n")
115
- Rbitter::Record.find_each { |t|
116
- f.write("#{t.marker},#{t.marker_msg},#{t.userid},#{t.username},#{t.tweetid},")
117
- f.write("#{t.replyto},#{t.tweet},#{t.date},#{t.rt_count},#{t.fav_count}\n")
118
- }
119
- }
120
- end
121
- end
1
+ # encoding: utf-8
2
+
3
+ require "active_record"
4
+ require "date"
5
+
6
+ module Rbitter
7
+ class Record < ActiveRecord::Base
8
+ end
9
+ end
10
+
11
+ module ARSupport
12
+ SCHEME_VERSION = 20150504
13
+ SCHEME = {
14
+ :marker => :integer, # 0 normal, 1 begin 2 halt
15
+ :marker_msg => :string,
16
+ :userid => :integer,
17
+ :username => :string,
18
+ :tweetid => :integer,
19
+ :replyto => :integer,
20
+ :tweet => :text, # with url unpacked
21
+ :date => :datetime,
22
+ :rt_count => :integer,
23
+ :fav_count => :integer
24
+ }
25
+
26
+ module_function
27
+ def prepared?
28
+ ActiveRecord::Base.connection.table_exists?(:records)
29
+ end
30
+
31
+ def connect_database
32
+ if Rbitter['activerecord'] == 'sqlite3'
33
+ warn "Warning: If you enable XMLRPC access, using sqlite is not recommended."
34
+ warn "Warning: Random crash can happen because of concurrency."
35
+
36
+ if RUBY_PLATFORM == 'java'
37
+ require "jdbc/sqlite3"
38
+ Jdbc::SQLite3.load_driver
39
+ ActiveRecord::Base.establish_connection(
40
+ adapter: 'jdbcsqlite3',
41
+ database: Rbitter['sqlite3']['dbfile'],
42
+ timeout: 10000) # Long timeout for slow computer
43
+ else
44
+ ActiveRecord::Base.establish_connection(
45
+ adapter: 'sqlite3',
46
+ database: Rbitter['sqlite3']['dbfile'],
47
+ timeout: 10000) # Long timeout for slow computer
48
+ end
49
+ elsif Rbitter['activerecord'] == 'mysql2'
50
+ Jdbc::MySQL.load_driver if RUBY_PLATFORM == 'java'
51
+
52
+ ActiveRecord::Base.establish_connection(
53
+ adapter: (RUBY_PLATFORM == 'java' ? 'jdbcmysql' : 'mysql2'),
54
+ host: Rbitter['mysql2']['host'],
55
+ port: Rbitter['mysql2']['port'],
56
+ database: Rbitter['mysql2']['dbname'],
57
+ username: Rbitter['mysql2']['username'],
58
+ password: Rbitter['mysql2']['password'],
59
+ encoding: "utf8mb4",
60
+ collation: "utf8mb4_unicode_ci")
61
+ else
62
+ raise RuntimeException.new("Unknown configuration value. 'activerecord' value should be sqlite3 or mysql2.")
63
+ end
64
+ end
65
+
66
+ def update_database_scheme
67
+ current_version = ActiveRecord::Migrator.current_version
68
+ if current_version < SCHEME_VERSION
69
+ warn "[records] Your ActiveRecord scheme is outdated."
70
+ warn "[records] Migrate... #{current_version} => #{SCHEME_VERSION}"
71
+ ActiveRecord::Migrator.migrate(File.expand_path("../records_migrate", __FILE__), SCHEME_VERSION)
72
+ end
73
+ end
74
+
75
+ def prepare option_string=""
76
+ ActiveRecord::Schema.define(version: SCHEME_VERSION) {
77
+ # MySQL specific option_string:
78
+ # utf8mb4 -> supporting UTF-8 4-byte characters (i.e. Emoji)
79
+ create_table(:records, { :options => option_string }) do |t|
80
+ SCHEME.each_key { |column|
81
+ case SCHEME[column]
82
+ when :string
83
+ t.string column
84
+ when :integer
85
+ t.integer column, :limit => 8
86
+ when :datetime
87
+ t.datetime column
88
+ when :text
89
+ t.text column
90
+ else
91
+ puts "Unexpected column type '#{SCHEME[column]}' of #{column}"
92
+ end
93
+ }
94
+ end
95
+
96
+ add_index :records, :tweetid
97
+ }
98
+ end
99
+
100
+ def any_to_datestring(obj)
101
+ if obj.is_a?(String)
102
+ # try to parse it
103
+ DateTime.parse(obj).strftime("%Y-%m-%d %H:%M:%S")
104
+ elsif obj.is_a?(DateTime) or obj.is_a?(Time)
105
+ obj.strftime("%Y-%m-%d %H:%M:%S")
106
+ else
107
+ raise ArgumentError.new("Can\'t automatically extract DateTime info")
108
+ end
109
+ end
110
+
111
+ def export_to_csv(csvfile)
112
+ open(csvfile, 'w') { |f|
113
+ f.write("marker,marker_msg,userid,username,tweetid,replyto,tweet,date,rt_count,fav_count")
114
+ f.write("\n")
115
+ Rbitter::Record.find_each { |t|
116
+ f.write("#{t.marker},#{t.marker_msg},#{t.userid},#{t.username},#{t.tweetid},")
117
+ f.write("#{t.replyto},#{t.tweet},#{t.date},#{t.rt_count},#{t.fav_count}\n")
118
+ }
119
+ }
120
+ end
121
+ end
@@ -1,12 +1,12 @@
1
- # encoding: utf-8
2
-
3
-
4
- class AddIndex < ActiveRecord::Migration
5
- def up
6
- add_index :records, :tweetid
7
- end
8
-
9
- def change
10
- up
11
- end
1
+ # encoding: utf-8
2
+
3
+
4
+ class AddIndex < ActiveRecord::Migration
5
+ def up
6
+ add_index :records, :tweetid
7
+ end
8
+
9
+ def change
10
+ up
11
+ end
12
12
  end
@@ -1,12 +1,12 @@
1
- # encoding: utf-8
2
-
3
-
4
- class AddReplytoColumn < ActiveRecord::Migration
5
- def up
6
- add_column :records, :replyto, :integer, :limit => 8
7
- end
8
-
9
- def change
10
- up
11
- end
1
+ # encoding: utf-8
2
+
3
+
4
+ class AddReplytoColumn < ActiveRecord::Migration
5
+ def up
6
+ add_column :records, :replyto, :integer, :limit => 8
7
+ end
8
+
9
+ def change
10
+ up
11
+ end
12
12
  end
@@ -1,105 +1,105 @@
1
- # encoding: utf-8
2
-
3
- require 'twitter'
4
-
5
- module Rbitter
6
- class DummyStreamClient
7
- def initialize(tokens); end
8
-
9
- def run(&operation_block)
10
- internal(&operation_block)
11
- end
12
-
13
- private
14
- def internal(&operation_block)
15
- tweets = [{
16
- "tweetid" => 1,
17
- "userid" => 1,
18
- "replyto" => nil,
19
- "tweet" => "test",
20
- "rt_count" => 0,
21
- "fav_count" => 0,
22
- "screen_name" => "twitter",
23
- "date" => "2015-01-01 12:11:10",
24
- "media_urls" => ["https://pbs.twimg.com/media/CEPWFtgUgAEmbcV.png"],
25
- "web_urls" => ["https://www.google.com/"]
26
- }]
27
-
28
- tweets.each { |tweet|
29
- yield tweet
30
- }
31
- end
32
- end
33
-
34
- class StreamClient
35
- def initialize(tokens)
36
- @t = Twitter::Streaming::Client.new do |object|
37
- object.consumer_key = tokens['consumer_key']
38
- object.consumer_secret = tokens['consumer_secret']
39
- object.access_token = tokens['access_token']
40
- object.access_token_secret = tokens['access_token_secret']
41
- end
42
- end
43
-
44
- def run(&operation_block)
45
- begin
46
- internal(&operation_block)
47
- rescue EOFError => e
48
- puts "Network unreachable. Retry in 3 seconds..."
49
- sleep 3
50
- retry
51
- end
52
- end
53
-
54
- private
55
- def internal(&operation_block)
56
- @t.user do |tweet|
57
- if tweet.is_a?(Twitter::Tweet)
58
- if tweet.retweet?
59
- tweet = tweet.retweeted_tweet
60
- end
61
-
62
- text = tweet.full_text.gsub(/(\r\n|\n)/, '')
63
-
64
- # unpack uris and media links
65
- media_urls = Array.new
66
- web_urls = Array.new
67
-
68
- if tweet.entities?
69
- if tweet.media?
70
- tweet.media.each { |media|
71
- media_urls.push("#{media.media_uri_https}")
72
- text.gsub!("#{media.url}", "#{media.display_url}")
73
- }
74
- end
75
-
76
- text += " "
77
- text += media_urls.join(" ")
78
-
79
- if tweet.uris?
80
- tweet.uris.each { |uri|
81
- web_urls.push("#{uri.expanded_url}")
82
- text.gsub!("#{uri.url}", "#{uri.expanded_url}")
83
- }
84
- end
85
- end
86
-
87
- res = {
88
- "tweetid" => tweet.id,
89
- "userid" => tweet.user.id,
90
- "replyto" => tweet.in_reply_to_status_id? ? tweet.in_reply_to_status_id : nil,
91
- "tweet" => text,
92
- "rt_count" => tweet.retweet_count,
93
- "fav_count" => tweet.favorite_count,
94
- "screen_name" => tweet.user.screen_name,
95
- "date" => tweet.created_at,
96
- "media_urls" => media_urls,
97
- "web_urls" => web_urls
98
- }
99
-
100
- yield res
101
- end
102
- end
103
- end
104
- end
1
+ # encoding: utf-8
2
+
3
+ require 'twitter'
4
+
5
+ module Rbitter
6
+ class DummyStreamClient
7
+ def initialize(tokens); end
8
+
9
+ def run(&operation_block)
10
+ internal(&operation_block)
11
+ end
12
+
13
+ private
14
+ def internal(&operation_block)
15
+ tweets = [{
16
+ "tweetid" => 1,
17
+ "userid" => 1,
18
+ "replyto" => nil,
19
+ "tweet" => "test",
20
+ "rt_count" => 0,
21
+ "fav_count" => 0,
22
+ "screen_name" => "twitter",
23
+ "date" => "2015-01-01 12:11:10",
24
+ "media_urls" => ["https://pbs.twimg.com/media/CEPWFtgUgAEmbcV.png"],
25
+ "web_urls" => ["https://www.google.com/"]
26
+ }]
27
+
28
+ tweets.each { |tweet|
29
+ yield tweet
30
+ }
31
+ end
32
+ end
33
+
34
+ class StreamClient
35
+ def initialize(tokens)
36
+ @t = Twitter::Streaming::Client.new do |object|
37
+ object.consumer_key = tokens['consumer_key']
38
+ object.consumer_secret = tokens['consumer_secret']
39
+ object.access_token = tokens['access_token']
40
+ object.access_token_secret = tokens['access_token_secret']
41
+ end
42
+ end
43
+
44
+ def run(&operation_block)
45
+ begin
46
+ internal(&operation_block)
47
+ rescue EOFError => e
48
+ puts "Network unreachable. Retry in 3 seconds..."
49
+ sleep 3
50
+ retry
51
+ end
52
+ end
53
+
54
+ private
55
+ def internal(&operation_block)
56
+ @t.user do |tweet|
57
+ if tweet.is_a?(Twitter::Tweet)
58
+ if tweet.retweet?
59
+ tweet = tweet.retweeted_tweet
60
+ end
61
+
62
+ text = tweet.full_text.gsub(/(\r\n|\n)/, '')
63
+
64
+ # unpack uris and media links
65
+ media_urls = Array.new
66
+ web_urls = Array.new
67
+
68
+ if tweet.entities?
69
+ if tweet.media?
70
+ tweet.media.each { |media|
71
+ media_urls.push("#{media.media_uri_https}")
72
+ text.gsub!("#{media.url}", "#{media.display_url}")
73
+ }
74
+ end
75
+
76
+ text += " "
77
+ text += media_urls.join(" ")
78
+
79
+ if tweet.uris?
80
+ tweet.uris.each { |uri|
81
+ web_urls.push("#{uri.expanded_url}")
82
+ text.gsub!("#{uri.url}", "#{uri.expanded_url}")
83
+ }
84
+ end
85
+ end
86
+
87
+ res = {
88
+ "tweetid" => tweet.id,
89
+ "userid" => tweet.user.id,
90
+ "replyto" => tweet.in_reply_to_status_id? ? tweet.in_reply_to_status_id : nil,
91
+ "tweet" => text,
92
+ "rt_count" => tweet.retweet_count,
93
+ "fav_count" => tweet.favorite_count,
94
+ "screen_name" => tweet.user.screen_name,
95
+ "date" => tweet.created_at,
96
+ "media_urls" => media_urls,
97
+ "web_urls" => web_urls
98
+ }
99
+
100
+ yield res
101
+ end
102
+ end
103
+ end
104
+ end
105
105
  end
@@ -1,20 +1,20 @@
1
- module Rbitter
2
- PRODUCT_NAME = "Rbitter"
3
- VERSION = "0.1.0"
4
-
5
- def major
6
- VERSION.match(/^([0-9]+)\./)[1]
7
- end
8
-
9
- def minor
10
- VERSION.match(/\.([0-9]+)\./)[1]
11
- end
12
-
13
- def patchlv
14
- VERSION.match(/\.([0-9]+)$/)[1]
15
- end
16
-
17
- def version_string
18
- "#{PRODUCT_NAME} #{VERSION}"
19
- end
20
- end
1
+ module Rbitter
2
+ PRODUCT_NAME = "Rbitter"
3
+ VERSION = "0.1.2"
4
+
5
+ def major
6
+ VERSION.match(/^([0-9]+)\./)[1]
7
+ end
8
+
9
+ def minor
10
+ VERSION.match(/\.([0-9]+)\./)[1]
11
+ end
12
+
13
+ def patchlv
14
+ VERSION.match(/\.([0-9]+)$/)[1]
15
+ end
16
+
17
+ def version_string
18
+ "#{PRODUCT_NAME} #{VERSION}"
19
+ end
20
+ end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
2
- #
3
-
1
+ # encoding: utf-8
2
+ #
3
+
4
4
  require "rbitter/xmlrpcd/xmlrpcd"
@@ -1,25 +1,25 @@
1
- # encoding: utf-8
2
-
3
- module RPCHandles
4
- RH_INFO = Struct.new("RPCHANDLE_INFO", :name, :version, :author, :description) {
5
- def digest
6
- "<rpchandle: #{name}-#{version} (written by #{author}, #{description})>"
7
- end
8
- }
9
-
10
- module BaseHandle
11
- # If a handler doesn't require an authorization, please inherit below class
12
- class NoAuth < Object
13
- def self.auth?
14
- false
15
- end
16
- end
17
-
18
- # If a handler does require an authorization, please inherit below class
19
- class Auth < Object
20
- def self.auth?
21
- true
22
- end
23
- end
24
- end
1
+ # encoding: utf-8
2
+
3
+ module RPCHandles
4
+ RH_INFO = Struct.new("RPCHANDLE_INFO", :name, :version, :author, :description) {
5
+ def digest
6
+ "<rpchandle: #{name}-#{version} (written by #{author}, #{description})>"
7
+ end
8
+ }
9
+
10
+ module BaseHandle
11
+ # If a handler doesn't require an authorization, please inherit below class
12
+ class NoAuth < Object
13
+ def self.auth?
14
+ false
15
+ end
16
+ end
17
+
18
+ # If a handler does require an authorization, please inherit below class
19
+ class Auth < Object
20
+ def self.auth?
21
+ true
22
+ end
23
+ end
24
+ end
25
25
  end
@@ -1,12 +1,12 @@
1
- # encoding: utf-8
2
-
3
- module RPCHandles
4
- # Override this function will activate authentication feature.
5
- # You can write and add RPCHandle. See 'rpc' folder.
6
-
7
- @@auth_pool = nil
8
- module_function
9
- def auth
10
- @@auth_pool
11
- end
1
+ # encoding: utf-8
2
+
3
+ module RPCHandles
4
+ # Override this function will activate authentication feature.
5
+ # You can write and add RPCHandle. See 'rpc' folder.
6
+
7
+ @@auth_pool = nil
8
+ module_function
9
+ def auth
10
+ @@auth_pool
11
+ end
12
12
  end