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,93 +1,93 @@
1
- # encoding: utf-8
2
- #
3
- # Rbitter Archive Access console (irb)
4
-
5
- require "xmlrpc/client"
6
- require "rbitter/version"
7
- require "ripl"
8
-
9
- module Rbitter
10
- class Console
11
- def initialize
12
- puts "Rbitter console #{Rbitter::VERSION}"
13
- help
14
- end
15
-
16
- def help
17
- puts "Predefined methods:"
18
- puts "ar - shortcut to call Rbitter::Record"
19
- puts "connect_ar - Prepare Rbitter::Record to be ready"
20
- puts "csv_backup - export Rbitter::Record into comma-separated values"
21
- puts "help - to show this message again"
22
- puts "xmlrpc - send xmlrpc command to destination"
23
- puts "xmlrpc_dest - set destination for xmlrpc command"
24
- puts "^D, 'exit' to exit from here"
25
- end
26
-
27
- def connect_ar
28
- ARSupport.connect_database
29
- puts "Rbitter::Record is ready."
30
- end
31
-
32
- def csv_backup *args
33
- if args.length < 0
34
- puts "Usage: csv_backup('filename.csv')"
35
- puts "Estimated running time depends on system environment"
36
- else
37
- ARSupport.export_to_csv(args[0])
38
- end
39
- end
40
-
41
- def ar
42
- Rbitter::Record
43
- end
44
-
45
- def exit
46
- Kernel.exit(0)
47
- end
48
-
49
- def xmlrpc_dest args={}
50
- if args.empty?
51
- puts "Usage: xmlrpc_dest({ :rpchost => '', :rpcpath => '', :rpcport => 1400,"
52
- puts " :xmlrpc_auth_id => '', xmlrpc_auth_password => '' })"
53
- end
54
-
55
- @rpchost = args.fetch(:rpchost) { "127.0.0.1" }
56
- @rpcpath = args.fetch(:rpcpath) { "/" }
57
- @rpcport = args.fetch(:rpcport) { 1400 }
58
-
59
- cl = XMLRPC::Client.new(@rpchost, @rpcpath, @rpcport)
60
- @xmlrpc_cookie = "auth_key=" + cl.call('rbitter.auth',
61
- args.fetch(:xmlrpc_auth_id) { Rbitter.env['xmlrpc']['auth'][0] },
62
- args.fetch(:xmlrpc_auth_password) { Rbitter.env['xmlrpc']['auth'][1] } )
63
-
64
- if @xmlrpc_cookie != "auth_key="
65
- puts "Authentication completed"
66
- else
67
- puts "Authentication failed"
68
- end
69
- end
70
-
71
- def xmlrpc *args
72
- if args.empty?
73
- puts "Usage: xmlrpc(command, [params in Array])"
74
- puts "Ex) xmlrpc(\'rbitter.echo\',' [\"Hello World!\"])"
75
- puts "Please configure XMLRPC destination with xmlrpc_dest method"
76
- return false
77
- end
78
-
79
- cl = XMLRPC::Client.new(@rpchost, @rpcpath, @rpcport, @xmlrpc_cookie)
80
-
81
- if args.length <= 1 or args[1].nil?
82
- cl.call(args[0])
83
- else
84
- cl.call(args[0], *args[1])
85
- end
86
- end
87
-
88
- def start
89
- Ripl.start :binding => binding
90
- end
91
- end
92
- end
93
-
1
+ # encoding: utf-8
2
+ #
3
+ # Rbitter Archive Access console (irb)
4
+
5
+ require "xmlrpc/client"
6
+ require "rbitter/version"
7
+ require "ripl"
8
+
9
+ module Rbitter
10
+ class Console
11
+ def initialize
12
+ puts "Rbitter console #{Rbitter::VERSION}"
13
+ help
14
+ end
15
+
16
+ def help
17
+ puts "Predefined methods:"
18
+ puts "ar - shortcut to call Rbitter::Record"
19
+ puts "connect_ar - Prepare Rbitter::Record to be ready"
20
+ puts "csv_backup - export Rbitter::Record into comma-separated values"
21
+ puts "help - to show this message again"
22
+ puts "xmlrpc - send xmlrpc command to destination"
23
+ puts "xmlrpc_dest - set destination for xmlrpc command"
24
+ puts "^D, 'exit' to exit from here"
25
+ end
26
+
27
+ def connect_ar
28
+ ARSupport.connect_database
29
+ puts "Rbitter::Record is ready."
30
+ end
31
+
32
+ def csv_backup *args
33
+ if args.length < 0
34
+ puts "Usage: csv_backup('filename.csv')"
35
+ puts "Estimated running time depends on system environment"
36
+ else
37
+ ARSupport.export_to_csv(args[0])
38
+ end
39
+ end
40
+
41
+ def ar
42
+ Rbitter::Record
43
+ end
44
+
45
+ def exit
46
+ Kernel.exit(0)
47
+ end
48
+
49
+ def xmlrpc_dest args={}
50
+ if args.empty?
51
+ puts "Usage: xmlrpc_dest({ :rpchost => '', :rpcpath => '', :rpcport => 1400,"
52
+ puts " :xmlrpc_auth_id => '', xmlrpc_auth_password => '' })"
53
+ end
54
+
55
+ @rpchost = args.fetch(:rpchost) { "127.0.0.1" }
56
+ @rpcpath = args.fetch(:rpcpath) { "/" }
57
+ @rpcport = args.fetch(:rpcport) { 1400 }
58
+
59
+ cl = XMLRPC::Client.new(@rpchost, @rpcpath, @rpcport)
60
+ @xmlrpc_cookie = "auth_key=" + cl.call('rbitter.auth',
61
+ args.fetch(:xmlrpc_auth_id) { Rbitter.env['xmlrpc']['auth'][0] },
62
+ args.fetch(:xmlrpc_auth_password) { Rbitter.env['xmlrpc']['auth'][1] } )
63
+
64
+ if @xmlrpc_cookie != "auth_key="
65
+ puts "Authentication completed"
66
+ else
67
+ puts "Authentication failed"
68
+ end
69
+ end
70
+
71
+ def xmlrpc *args
72
+ if args.empty?
73
+ puts "Usage: xmlrpc(command, [params in Array])"
74
+ puts "Ex) xmlrpc(\'rbitter.echo\',' [\"Hello World!\"])"
75
+ puts "Please configure XMLRPC destination with xmlrpc_dest method"
76
+ return false
77
+ end
78
+
79
+ cl = XMLRPC::Client.new(@rpchost, @rpcpath, @rpcport, @xmlrpc_cookie)
80
+
81
+ if args.length <= 1 or args[1].nil?
82
+ cl.call(args[0])
83
+ else
84
+ cl.call(args[0], *args[1])
85
+ end
86
+ end
87
+
88
+ def start
89
+ Ripl.start :binding => binding
90
+ end
91
+ end
92
+ end
93
+
@@ -1,38 +1,37 @@
1
- module Rbitter
2
- DEFAULT_CONFIG_JSON = <<-ENDOFJSON
3
- {
4
- "twitter": {
5
- "consumer_key": "",
6
- "consumer_secret": "",
7
- "access_token": "",
8
- "access_token_secret": ""
9
- },
10
- "activerecord": "sqlite3",
11
- "sqlite3": {
12
- "dbfile": "rbitter.sqlite"
13
- },
14
- "mysql2": {
15
- "host": "localhost",
16
- "port": 3306,
17
- "dbname": "archive",
18
- "username": "",
19
- "password": ""
20
- },
21
- "media_downloader": {
22
- "large_image": true,
23
- "cacert_path": "/cacerts/cacert.pem",
24
- "download_dir": "imgs/"
25
- },
26
- "xmlrpc": {
27
- "enable": true,
28
- "bind_host": "0.0.0.0",
29
- "bind_port": 1400,
30
- "auth": {
31
- "username": "username",
32
- "password": "password"
33
- },
34
- "handles": ["/path/to/handles"]
35
- }
36
- }
37
- ENDOFJSON
38
- end
1
+ module Rbitter
2
+ DEFAULT_CONFIG_JSON = <<-ENDOFJSON
3
+ {
4
+ "twitter": {
5
+ "consumer_key": "",
6
+ "consumer_secret": "",
7
+ "access_token": "",
8
+ "access_token_secret": ""
9
+ },
10
+ "activerecord": "sqlite3",
11
+ "sqlite3": {
12
+ "dbfile": "rbitter.sqlite"
13
+ },
14
+ "mysql2": {
15
+ "host": "localhost",
16
+ "port": 3306,
17
+ "dbname": "archive",
18
+ "username": "",
19
+ "password": ""
20
+ },
21
+ "media_downloader": {
22
+ "large_image": true,
23
+ "download_dir": "imgs/"
24
+ },
25
+ "xmlrpc": {
26
+ "enable": true,
27
+ "bind_host": "0.0.0.0",
28
+ "bind_port": 1400,
29
+ "auth": {
30
+ "username": "username",
31
+ "password": "password"
32
+ },
33
+ "handles": ["/path/to/handles"]
34
+ }
35
+ }
36
+ ENDOFJSON
37
+ end
@@ -1,66 +1,63 @@
1
- # encoding: utf-8
2
-
3
- require "net/http"
4
- require "openssl"
5
-
6
- module Rbitter
7
- class DLThread
8
- def initialize(dlfolder, cacert_path, large_flag)
9
- @dest = dlfolder
10
- if not File.directory?(dlfolder)
11
- warn "[dlthread] Given download location is not available for downloading."
12
- warn "[dlthread] Fallback to current directory."
13
- @dest = "./"
14
- end
15
-
16
- @cacert = cacert_path
17
- if large_flag.nil?
18
- @large_image = false
19
- else
20
- @large_image = large_flag
21
- end
22
-
23
- @pool = Array.new
24
- end
25
-
26
- def <<(url_array)
27
- download_task = Thread.new {
28
- url_array.each { |url|
29
- uri = URI.parse(@large_image ? url + ":large" : url)
30
- http = Net::HTTP.new(uri.host, uri.port)
31
- if uri.scheme.downcase == 'https'
32
- http.use_ssl = true
33
- http.ca_path = @cacert
34
- end
35
-
36
- http.request_get(uri.path) { |res|
37
- case res
38
- when Net::HTTPOK
39
- fname = File.basename(url)
40
-
41
- puts "[fetch] remote: #{uri.path} => local: #{fname}"
42
- open(File.join(@dest, fname), "wb") { |file|
43
- res.read_body { |chunk| file.write(chunk) }
44
- }
45
- end
46
- }
47
- }
48
- }
49
-
50
- @pool.push download_task
51
- end
52
-
53
- def job_cleanup
54
- until @pool.empty?
55
- puts "[dlthread] Thread forceful cleaning up [remains: #{@pool.length}]"
56
-
57
- dlthrd = @pool.shift
58
-
59
- if dlthrd.alive?
60
- dlthrd.terminate
61
- dlthrd.join
62
- end
63
- end
64
- end
65
- end
1
+ # encoding: utf-8
2
+
3
+ require "net/http"
4
+ require "openssl"
5
+
6
+ module Rbitter
7
+ class DLThread
8
+ def initialize(dlfolder, large_flag)
9
+ @dest = dlfolder
10
+ if not File.directory?(dlfolder)
11
+ warn "[dlthread] Given download location is not available for downloading."
12
+ warn "[dlthread] Fallback to current directory."
13
+ @dest = "./"
14
+ end
15
+
16
+ if large_flag.nil?
17
+ @large_image = false
18
+ else
19
+ @large_image = large_flag
20
+ end
21
+
22
+ @pool = Array.new
23
+ end
24
+
25
+ def <<(url_array)
26
+ download_task = Thread.new {
27
+ url_array.each { |url|
28
+ uri = URI.parse(@large_image ? url + ":large" : url)
29
+ ssl = uri.scheme.downcase == 'https'
30
+
31
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => ssl) { |h|
32
+ req = Net::HTTP::Get.new uri.request_uri
33
+ h.request(req) { |res|
34
+ case res
35
+ when Net::HTTPOK
36
+ fname = File.basename(url)
37
+
38
+ puts "[fetch] remote: #{uri.path} => local: #{fname}"
39
+ open(File.join(@dest, fname), "wb") { |file|
40
+ res.read_body { |chunk| file.write(chunk) }
41
+ }
42
+ end
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ @pool.push download_task
49
+ end
50
+
51
+ def job_cleanup
52
+ until @pool.empty?
53
+ dlthrd = @pool.shift
54
+
55
+ if dlthrd.alive?
56
+ puts "[dlthread] Thread forceful cleaning up [remains: #{@pool.length}]"
57
+ dlthrd.terminate
58
+ dlthrd.join
59
+ end
60
+ end
61
+ end
62
+ end
66
63
  end
data/lib/rbitter/env.rb CHANGED
@@ -1,62 +1,62 @@
1
- # encoding: utf-8
2
-
3
- require "json"
4
-
5
- module Rbitter
6
- @@env = Hash.new
7
-
8
- class ConfigFileError < StandardError; end
9
-
10
- def self.[](k)
11
- @@env[k]
12
- end
13
-
14
- module_function
15
- def env
16
- @@env
17
- end
18
-
19
- def env_reset
20
- @@env.clear
21
- end
22
-
23
- def env_validate?
24
- # TODO: Add validator
25
- true
26
- end
27
-
28
- def config_initialize json_path=nil
29
- env_reset
30
-
31
- unless json_path.nil?
32
- begin
33
- open(json_path, 'r') { |file|
34
- @@env = JSON.parse(file.read)
35
- }
36
-
37
- return @@env if env_validate?
38
- fail StandardError, "Invalid configuration"
39
- rescue => e
40
- fail ConfigFileError, "Load Failure (#{json_path}): #{e.to_s}"
41
- end
42
- end
43
-
44
- # Configuration default location
45
- # 1. (current_dir)/config.json
46
- # 2. (current_dir)/.rbitter/config.json
47
- locations = ["config.json", ".rbitter/config.json"]
48
- locations.collect! { |base| File.join(Dir.pwd, base) }
49
-
50
- for location in locations
51
- next unless File.file?(location)
52
- open(location, 'r') { |file|
53
- @@env = JSON.parse(file.read)
54
- }
55
- break if env_validate?
56
- end
57
-
58
- if @@env.empty?
59
- fail ConfigFileError, "Can not load any configuration in [#{locations.join(', ')}]"
60
- end
61
- end
62
- end
1
+ # encoding: utf-8
2
+
3
+ require "json"
4
+
5
+ module Rbitter
6
+ @@env = Hash.new
7
+
8
+ class ConfigFileError < StandardError; end
9
+
10
+ def self.[](k)
11
+ @@env[k]
12
+ end
13
+
14
+ module_function
15
+ def env
16
+ @@env
17
+ end
18
+
19
+ def env_reset
20
+ @@env.clear
21
+ end
22
+
23
+ def env_validate?
24
+ # TODO: Add validator
25
+ true
26
+ end
27
+
28
+ def config_initialize json_path=nil
29
+ env_reset
30
+
31
+ unless json_path.nil?
32
+ begin
33
+ open(json_path, 'r') { |file|
34
+ @@env = JSON.parse(file.read)
35
+ }
36
+
37
+ return @@env if env_validate?
38
+ fail StandardError, "Invalid configuration"
39
+ rescue => e
40
+ fail ConfigFileError, "Load Failure (#{json_path}): #{e.to_s}"
41
+ end
42
+ end
43
+
44
+ # Configuration default location
45
+ # 1. (current_dir)/config.json
46
+ # 2. (current_dir)/.rbitter/config.json
47
+ locations = ["config.json", ".rbitter/config.json"]
48
+ locations.collect! { |base| File.join(Dir.pwd, base) }
49
+
50
+ for location in locations
51
+ next unless File.file?(location)
52
+ open(location, 'r') { |file|
53
+ @@env = JSON.parse(file.read)
54
+ }
55
+ break if env_validate?
56
+ end
57
+
58
+ if @@env.empty?
59
+ fail ConfigFileError, "Can not load any configuration in [#{locations.join(', ')}]"
60
+ end
61
+ end
62
+ end
@@ -1,46 +1,46 @@
1
- # encoding: utf-8
2
-
3
- require 'http/parser'
4
- require 'openssl'
5
- require 'resolv'
6
-
7
- module Twitter
8
- module Streaming
9
- class Connection
10
- MODIFIED = true
11
- attr_reader :tcp_socket_class, :ssl_socket_class
12
-
13
- def initialize(options = {})
14
- @tcp_socket_class = options.fetch(:tcp_socket_class) { TCPSocket }
15
- @ssl_socket_class = options.fetch(:ssl_socket_class) { OpenSSL::SSL::SSLSocket }
16
- end
17
-
18
- def stream(request, response)
19
- client_context = OpenSSL::SSL::SSLContext.new
20
- client = @tcp_socket_class.new(Resolv.getaddress(request.uri.host), request.uri.port)
21
- ssl_client = @ssl_socket_class.new(client, client_context)
22
- ssl_client.connect
23
- request.stream(ssl_client)
24
-
25
- loop {
26
- begin
27
- body = ssl_client.read_nonblock(1024) # rubocop:disable AssignmentInCondition, WhileUntilModifier
28
- response << body
29
- rescue IO::WaitReadable
30
- # The reason for setting 90 seconds as a timeout is documented on:
31
- # https://dev.twitter.com/streaming/overview/connecting
32
- r, w, e = IO.select([ssl_client], [], [], 90)
33
- if r.nil?
34
- # If timeout occurs
35
- ssl_client.close
36
- raise Twitter::Error::ServerError.new("Connection stalled")
37
- else
38
- # If socket is readable
39
- retry
40
- end
41
- end
42
- }
43
- end
44
- end
45
- end
1
+ # encoding: utf-8
2
+
3
+ require 'http/parser'
4
+ require 'openssl'
5
+ require 'resolv'
6
+
7
+ module Twitter
8
+ module Streaming
9
+ class Connection
10
+ MODIFIED = true
11
+ attr_reader :tcp_socket_class, :ssl_socket_class
12
+
13
+ def initialize(options = {})
14
+ @tcp_socket_class = options.fetch(:tcp_socket_class) { TCPSocket }
15
+ @ssl_socket_class = options.fetch(:ssl_socket_class) { OpenSSL::SSL::SSLSocket }
16
+ end
17
+
18
+ def stream(request, response)
19
+ client_context = OpenSSL::SSL::SSLContext.new
20
+ client = @tcp_socket_class.new(Resolv.getaddress(request.uri.host), request.uri.port)
21
+ ssl_client = @ssl_socket_class.new(client, client_context)
22
+ ssl_client.connect
23
+ request.stream(ssl_client)
24
+
25
+ loop {
26
+ begin
27
+ body = ssl_client.read_nonblock(1024) # rubocop:disable AssignmentInCondition, WhileUntilModifier
28
+ response << body
29
+ rescue IO::WaitReadable
30
+ # The reason for setting 90 seconds as a timeout is documented on:
31
+ # https://dev.twitter.com/streaming/overview/connecting
32
+ r, w, e = IO.select([ssl_client], [], [], 90)
33
+ if r.nil?
34
+ # If timeout occurs
35
+ ssl_client.close
36
+ raise Twitter::Error::ServerError.new("Connection stalled")
37
+ else
38
+ # If socket is readable
39
+ retry
40
+ end
41
+ end
42
+ }
43
+ end
44
+ end
45
+ end
46
46
  end