rbitter 0.1.2 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3ca2dd0e8a08659416b4e1ba154375673bfe697d
4
- data.tar.gz: d60daa351fef6fdfa8cc3fdb444b31e10a820c80
3
+ metadata.gz: c258b870ebf4e8dd9304ce2cfc588cf720fba7c1
4
+ data.tar.gz: 0a86c5194600ef1964ec08ae923e8abd9a6b7740
5
5
  SHA512:
6
- metadata.gz: 251d4bda5d89583701ca2ecb3b52c5cafeab42b6e3f01d90692e2457d48f53e22ff9cda790daed72b63088cd077c4ba7ba27e8dd0751e9d2b5f1dbbf68dd1286
7
- data.tar.gz: cb04a2013000e2581b5b8c6dd5b30b15058c6f70f995fbde2dbf31733e78a23c7b8526cafc203cae9d0125f16752c8728cc45b3103f28a83e2d52dbac153118e
6
+ metadata.gz: 211b5214c71b22df1d0d0f944760bc8f3c2518e1e9552d044e72c3606bb4fa158422da7330406ecd8885a0ddcf6defe416606176efa75ed16836c9f316cefb6a
7
+ data.tar.gz: d6f73a9ca34b941c0de31a4153a0b9144425dd0279b699f9aa60ff35c6bcbe312799f03ec6ff3c62d2021bc1ed380885aa072437cfa723e115d686c486f9dcbc
data/.gitignore CHANGED
@@ -17,5 +17,6 @@ mkmf.log
17
17
  *.gem
18
18
  *.json
19
19
  *.sqlite
20
+ *.png
20
21
  .rbitter
21
22
  .rbitter/*
data/README.md CHANGED
@@ -30,6 +30,11 @@ Put your customized config.json to one of below locations.
30
30
  1. ./config.json (current folder)
31
31
  2. ./.rbitter/config.json (current folder)
32
32
 
33
+ ### XMLRPC handlers ###
34
+ To get XMLRPC handlers, visit [Rbitter XMLRPC](https://github.com/nidev/rbitter-rpchandles).
35
+
36
+ You can find the document to write your own XMLRPC handler.
37
+
33
38
  ## Set up and run ##
34
39
  With config.json,
35
40
 
@@ -42,9 +47,6 @@ With config.json,
42
47
  ```bash
43
48
  $ rbitter serve
44
49
  ```
45
- ## XMLRPC API ##
46
-
47
- See XMLRPC.md
48
50
 
49
51
  ## TODO ##
50
52
  * Streaming Client
data/lib/rbitter.rb CHANGED
@@ -6,6 +6,7 @@ require "rbitter/arcserver"
6
6
  require "rbitter/env"
7
7
  require "rbitter/console"
8
8
  require "rbitter/xmlrpc"
9
+ require "rbitter/override"
9
10
 
10
11
  module Rbitter
11
12
  BOOTSTRAP_ARGS = ['configure', 'console', 'help', 'logs', 'serve']
@@ -26,29 +27,6 @@ module Rbitter
26
27
  puts "`- logs : Show Rbitter internal logs"
27
28
  end
28
29
 
29
- def self.prebootstrap
30
- # Due to stalled socket problem, If unpatched twitter gem is installed.
31
- # Twitter::Streaming::Connection will be monkey-patched.
32
- patch_required = false
33
-
34
- if Twitter::Version.const_defined?(:MAJOR)
35
- b5_version = Twitter::Version::MAJOR * 10000
36
- + Twitter::Version::MINOR * 100 + Twitter::Version::PATCH
37
- if b5_version <= 51400
38
- warn "[rbitter] Monkey-patching Twitter::Streaming::Connection"
39
- warn "[rbitter] Please upgrade twitter gem to apply streaming read timeout"
40
- patch_required = true
41
- end
42
- else
43
- b6_version = Twitter::Version.to_a
44
- if b6_version[0] <= 6 and b6_version[1] <= 0 and b6_version[2] <= 0
45
- patch_required = true
46
- end
47
- end
48
-
49
- require "rbitter/libtwitter_connection_override" if patch_required
50
- end
51
-
52
30
  def self.bootstrap_configs
53
31
  require "rbitter/default/config_json"
54
32
 
@@ -61,8 +39,6 @@ module Rbitter
61
39
  return nil if args.length < 1
62
40
 
63
41
  if args[0] == "serve"
64
- prebootstrap
65
-
66
42
  Rbitter.config_initialize
67
43
 
68
44
  archive_server = Rbitter::ArcServer.new
@@ -15,10 +15,16 @@ module Rbitter
15
15
  LOG_NORMAL = 0
16
16
  LOG_INIT = 1
17
17
  LOG_HALT = 2
18
+ LOG_ERROR = 4
18
19
 
19
20
  def initialize(xmlrpcd_class = Rbitter::RPCServer)
20
21
  @xmlrpcd_class = xmlrpcd_class
22
+ @dt = DLThread.new(
23
+ Rbitter['media_downloader']['download_dir'],
24
+ Rbitter['media_downloader']['large_image'])
25
+ end
21
26
 
27
+ def arsupport_init
22
28
  ARSupport.connect_database
23
29
 
24
30
  if not ARSupport.prepared?
@@ -31,10 +37,10 @@ module Rbitter
31
37
  end
32
38
 
33
39
  ARSupport.update_database_scheme
40
+ end
34
41
 
35
- @dt = DLThread.new(
36
- Rbitter['media_downloader']['download_dir'],
37
- Rbitter['media_downloader']['large_image'])
42
+ def arsupport_halt
43
+ ARSupport.disconnect_database
38
44
  end
39
45
 
40
46
  def xmlrpcd_start
@@ -72,21 +78,38 @@ module Rbitter
72
78
  :fav_count => 0})
73
79
  end
74
80
 
75
- def write_init_marker
81
+ def mark_init
76
82
  mark(LOG_INIT, "Archiving service started")
77
83
  end
78
84
 
79
- def write_halt_marker
85
+ def mark_halt
80
86
  mark(LOG_HALT, "Archiving service halted")
81
87
  end
82
88
 
89
+ def mark_error(exception_string, err_msg)
90
+ mark(LOG_ERROR, "Errored (#{exception_string}, #{err_msg}")
91
+ end
92
+
93
+ def resurrect_loop?
94
+ if Rbitter.env['twitter']['connection']['reconnect']
95
+ puts "[rbitter] Try to reconnect..."
96
+ sleep Rbitter.env['twitter']['connection']['timeout_secs']
97
+ true
98
+ else
99
+ puts "[rbitter] Give up!"
100
+ false
101
+ end
102
+ end
103
+
83
104
  def main_loop(streaming_adapter = Rbitter::StreamClient)
84
105
  xmlrpcd_start if Rbitter['xmlrpc']['enable']
85
106
 
107
+ arsupport_init
108
+
86
109
  begin
87
- write_init_marker
110
+ mark_init
88
111
 
89
- streaming_adapter.new(Rbitter['twitter'].dup).run { |a|
112
+ streaming_adapter.new(Rbitter['twitter']).run { |a|
90
113
  @dt << a['media_urls']
91
114
 
92
115
  record = Record.find_or_initialize_by(tweetid: a['tweetid'])
@@ -106,25 +129,37 @@ module Rbitter
106
129
  rescue Interrupt => e
107
130
  puts ""
108
131
  puts "Interrupted..."
132
+ mark_error(e.to_s, "(exit) SIGINT - interrupted by user")
109
133
  rescue Twitter::Error::Unauthorized => e
110
134
  warn "Twitter access unauthorized:"
111
135
  warn " Possible solutions"
112
136
  warn " 1. Configure Twitter token on config.json"
113
137
  warn " 2. Check system time (Time is important on authentication)"
114
138
  warn " 3. Check Twitter account status"
115
- rescue Twitter::Error::ServerError, Resolv::ResolvError => e
116
- puts "Service unavailable now. Retry in 5 second..."
117
- sleep 5
118
- retry
139
+ rescue Twitter::Error::ServerError => e
140
+ puts "Service unavailable now. Retry in 5 seconds..."
141
+ mark_error(e.to_s, "(retry) Twitter server unavailable / Timeout")
142
+
143
+ retry if resurrect_loop?
144
+ rescue Resolv::ResolvError, Errno::ECONNABORTED,
145
+ Errno::ECONNREFUSED, Errno::ECONNRESET => e
146
+ puts "Network problem. Retry in 5 seconds..."
147
+ mark_error(e.to_s, "(retry) Network problem")
148
+
149
+ retry if resurrect_loop?
119
150
  rescue Twitter::Error => e
120
151
  warn "Twitter Error: #{e.inspect}"
121
- warn "Main loop of ArcServer halted."
152
+ warn "Rbitter halts due to Twitter::Error"
153
+ mark_error(e.to_s, "(exit) Twitter Error")
122
154
  ensure
123
155
  xmlrpcd_stop if Rbitter['xmlrpc']['enable']
124
156
  @dt.job_cleanup
125
157
 
126
- write_halt_marker
158
+ mark_halt
127
159
  end
160
+
161
+ arsupport_halt
128
162
  end
163
+
129
164
  end
130
165
  end
@@ -5,7 +5,11 @@ module Rbitter
5
5
  "consumer_key": "",
6
6
  "consumer_secret": "",
7
7
  "access_token": "",
8
- "access_token_secret": ""
8
+ "access_token_secret": "",
9
+ "connection": {
10
+ "reconnect": true,
11
+ "timeout_secs": 5
12
+ }
9
13
  },
10
14
  "activerecord": "sqlite3",
11
15
  "sqlite3": {
data/lib/rbitter/env.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "json"
4
+ require "rbitter/default/config_json"
4
5
 
5
6
  module Rbitter
6
7
  @@env = Hash.new
7
8
 
8
9
  class ConfigFileError < StandardError; end
10
+ class MissingFieldError < StandardError; end
9
11
 
10
12
  def self.[](k)
11
13
  @@env[k]
@@ -20,9 +22,60 @@ module Rbitter
20
22
  @@env.clear
21
23
  end
22
24
 
23
- def env_validate?
24
- # TODO: Add validator
25
- true
25
+ def env_listfields hash
26
+ path_stack = ['']
27
+ generated = []
28
+
29
+ until path_stack.empty?
30
+ path = path_stack.pop
31
+
32
+ if path == ''
33
+ o = hash
34
+ else
35
+ nodes = path.strip.split('->')
36
+ o = hash
37
+ until nodes.empty?
38
+ o = o[nodes.shift]
39
+ end
40
+ end
41
+
42
+ o.each_key { |k|
43
+ if o[k].is_a?(Hash)
44
+ path_stack << "#{k}" if path.empty?
45
+ path_stack << path + "->#{k}" unless path.empty?
46
+ else
47
+ generated << "#{k}" if path.empty?
48
+ generated << path + "->#{k}" unless path.empty?
49
+ end
50
+ }
51
+ end
52
+
53
+ generated
54
+ end
55
+
56
+ def env_valid?
57
+ defaults = env_listfields(JSON.parse(DEFAULT_CONFIG_JSON))
58
+ currents = env_listfields(@@env)
59
+ not_errored = true
60
+
61
+ # Cross checking (2 phases)
62
+ # In current exists, default does not: redundant configuration
63
+ # Level: warning since it is not utilized at all.
64
+ currents.each { |conf|
65
+ unless defaults.include?(conf)
66
+ warn "[config.json] Unused config: #{conf}. You can safely remove it."
67
+ end
68
+ }
69
+
70
+ # In default exists, current does not: missing configuration
71
+ # Level: error and program should stop. (return false for this)
72
+ defaults.each { |conf|
73
+ unless currents.include?(conf)
74
+ warn "[config.json] Config not found: #{conf}. Invalid configuration!"
75
+ not_errored = false
76
+ end
77
+ }
78
+ not_errored
26
79
  end
27
80
 
28
81
  def config_initialize json_path=nil
@@ -34,7 +87,7 @@ module Rbitter
34
87
  @@env = JSON.parse(file.read)
35
88
  }
36
89
 
37
- return @@env if env_validate?
90
+ return @@env if env_valid?
38
91
  fail StandardError, "Invalid configuration"
39
92
  rescue => e
40
93
  fail ConfigFileError, "Load Failure (#{json_path}): #{e.to_s}"
@@ -52,11 +105,12 @@ module Rbitter
52
105
  open(location, 'r') { |file|
53
106
  @@env = JSON.parse(file.read)
54
107
  }
55
- break if env_validate?
108
+ break unless @@env.empty?
56
109
  end
57
110
 
58
- if @@env.empty?
59
- fail ConfigFileError, "Can not load any configuration in [#{locations.join(', ')}]"
60
- end
111
+ fail ConfigFileError, "No config.json on #{locations.join(' or ')}" if @@env.empty?
112
+ fail ConfigFileError, "Configuration outdated. Please see above messages to update it" if not env_valid?
113
+
114
+ puts "[config.json] Loaded configuration is valid. good to go!"
61
115
  end
62
116
  end
@@ -0,0 +1,47 @@
1
+ =begin
2
+ This module gives special workarounds for some issues.
3
+
4
+ Problems are bypassed by monkey-patching.
5
+
6
+ As soon as a problem is resolved, patch should be removed.
7
+
8
+ **** Known issues ****
9
+
10
+ 1. gem/twitter
11
+ Location : override/gem/twitter/connection.rb
12
+ Maintain : until below issue is fixed
13
+ Reference: https://github.com/sferik/twitter/pull/669
14
+
15
+ Gem 'twitter' does not handle streaming timeout. By applying this,
16
+ reading timeout works and Rbitter can handle timeouts.
17
+
18
+ 2. gem/rubysl-socket
19
+ Location : override/gem/rubysl-socket/socket.rb
20
+ Maintain : until ip_address_list is implemented
21
+ Reference: https://github.com/rubysl/rubysl-socket/pull/9
22
+
23
+ With ipv6 environment, Resolv#use_ipv6? (in rubysl-resolv gem) checks
24
+ Socket.ip_address_list. This is not implemented at all with rubysl-socket-2.0.1.
25
+ NoMethodError exception is raised instead of NotImplementedError.
26
+
27
+ By applying this, Socket.ip_address_list is implemented and the method throws
28
+ NotImplementedError exception.
29
+
30
+ =end
31
+
32
+ def gem_twitter_patcher
33
+ require 'rbitter/override/gems/twitter/connection'
34
+ end
35
+
36
+ if Twitter::Version.const_defined?(:MAJOR)
37
+ b5_version = Twitter::Version::MAJOR * 10000
38
+ + Twitter::Version::MINOR * 100 + Twitter::Version::PATCH
39
+ gem_twitter_patcher if b5_version <= 51400
40
+ else
41
+ b6_version = Twitter::Version.to_a
42
+ if b6_version[0] <= 6 and b6_version[1] <= 0 and b6_version[2] <= 0
43
+ gem_twitter_patcher
44
+ end
45
+ end
46
+
47
+ require 'rbitter/override/gems/rubysl-socket/socket' if RUBY_ENGINE == 'rbx'
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+ require 'socket'
3
+
4
+ class Socket
5
+ def self.ip_address_list
6
+ fail NotImplementedError
7
+ end
8
+ end
@@ -63,6 +63,12 @@ module ARSupport
63
63
  end
64
64
  end
65
65
 
66
+ def disconnect_database
67
+ if ActiveRecord::Base.connected?
68
+ ActiveRecord::Base.connection.close
69
+ end
70
+ end
71
+
66
72
  def update_database_scheme
67
73
  current_version = ActiveRecord::Migrator.current_version
68
74
  if current_version < SCHEME_VERSION
@@ -1,6 +1,6 @@
1
1
  module Rbitter
2
2
  PRODUCT_NAME = "Rbitter"
3
- VERSION = "0.1.2"
3
+ VERSION = "0.2.0"
4
4
 
5
5
  def major
6
6
  VERSION.match(/^([0-9]+)\./)[1]
@@ -53,10 +53,24 @@ describe Rbitter do
53
53
  end
54
54
  end
55
55
 
56
- context 'when env_validator validates loaded configuration' do
57
- # TODO: Perform test with spec/config/default.json
58
- # TODO: Adding configuration validator on env.rb
59
- end
56
+ context "when 'env_valid?' validates loaded configuration" do
57
+ before(:all) do
58
+ Rbitter.bootstrap(['configure'])
59
+ expect(File.file?('config.json')).to be(true)
60
+ end
61
+
62
+ it 'gets \'false\' for empty configuration' do
63
+ Rbitter.env_reset
64
+ expect(Rbitter.env_valid?).to be(false)
65
+ end
60
66
 
61
- # TODO: Perform test with spec/config/default.json
67
+ it "gets \'true\' with default and another default" do
68
+ Rbitter.config_initialize
69
+ expect(Rbitter.env_valid?).to be(true)
70
+ end
71
+
72
+ after(:all) do
73
+ File.delete('config.json')
74
+ end
75
+ end
62
76
  end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- require "rbitter/libtwitter_connection_override"
2
+ require "rbitter/override/gems/twitter/connection"
3
3
 
4
4
  describe Rbitter do
5
5
  it 'overrides twitter gem' do
data/spec/rbitter_spec.rb CHANGED
@@ -22,10 +22,6 @@ describe Rbitter do
22
22
  Rbitter.bootstrap(['configure'])
23
23
  end
24
24
 
25
- it 'executes prebootstrap properly' do
26
- Rbitter.prebootstrap
27
- end
28
-
29
25
  it 'bootstraps nothing when empty ARGV is given' do
30
26
  Rbitter.bootstrap([])
31
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbitter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nidev Plontra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-17 00:00:00.000000000 Z
11
+ date: 2015-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: twitter
@@ -152,7 +152,6 @@ files:
152
152
  - LICENSE.txt
153
153
  - README.md
154
154
  - Rakefile
155
- - XMLRPC.md
156
155
  - bin/rbitter
157
156
  - lib/rbitter.rb
158
157
  - lib/rbitter/arcserver.rb
@@ -160,7 +159,9 @@ files:
160
159
  - lib/rbitter/default/config_json.rb
161
160
  - lib/rbitter/dlthread.rb
162
161
  - lib/rbitter/env.rb
163
- - lib/rbitter/libtwitter_connection_override.rb
162
+ - lib/rbitter/override.rb
163
+ - lib/rbitter/override/gems/rubysl-socket/socket.rb
164
+ - lib/rbitter/override/gems/twitter/connection.rb
164
165
  - lib/rbitter/records.rb
165
166
  - lib/rbitter/records_migrate/.keep
166
167
  - lib/rbitter/records_migrate/20150327_add_index.rb
@@ -180,7 +181,8 @@ files:
180
181
  - spec/rbitter/default/config_json_spec.rb
181
182
  - spec/rbitter/dlthread_spec.rb
182
183
  - spec/rbitter/env_spec.rb
183
- - spec/rbitter/libtwitter_connection_override_spec.rb
184
+ - spec/rbitter/override/gems/rubysl-socket/socket_spec.rb
185
+ - spec/rbitter/override/gems/twitter/connection_spec.rb
184
186
  - spec/rbitter/records_spec.rb
185
187
  - spec/rbitter/streaming_spec.rb
186
188
  - spec/rbitter/version_spec.rb
@@ -224,7 +226,8 @@ test_files:
224
226
  - spec/rbitter/default/config_json_spec.rb
225
227
  - spec/rbitter/dlthread_spec.rb
226
228
  - spec/rbitter/env_spec.rb
227
- - spec/rbitter/libtwitter_connection_override_spec.rb
229
+ - spec/rbitter/override/gems/rubysl-socket/socket_spec.rb
230
+ - spec/rbitter/override/gems/twitter/connection_spec.rb
228
231
  - spec/rbitter/records_spec.rb
229
232
  - spec/rbitter/streaming_spec.rb
230
233
  - spec/rbitter/version_spec.rb
data/XMLRPC.md DELETED
@@ -1,19 +0,0 @@
1
- # What is RPC handle ? #
2
- ## Commands ##
3
- ### Authentication ###
4
- ### Revoke Authentication Token ###
5
- ### Echo ###
6
- ### Last Active ###
7
- ### Retriever ###
8
- ### Statistic ###
9
- # How to write own RPC handle? #
10
- RPC handle is a Ruby class. Writing a method in Ruby class, that's it. Names of methods are treated as XMLRPC command.
11
-
12
- When you write a new class for your own RPC handle, you must inherit either Auth or NoAuth class from rpc/base.rb.
13
-
14
- * class Auth < Object: Methods in a Ruby class inheriting Auth requires *auth_key* to access.
15
- * class NoAuth < Object: Methods in a Ruby class inheriting NoAuth doesn't require *auth_key* and these XMLRPC commands can be called by anonymous user.
16
-
17
- Filename should start with 'rh_'. It's prefix to be autoloaded by xmlrpc.rb.
18
-
19
- Refer rpc/rh_echo.rb as an example.