rbitter 0.1.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +15 -0
  5. data/Gemfile +12 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +72 -0
  8. data/Rakefile +8 -0
  9. data/XMLRPC.md +19 -0
  10. data/bin/rbitter +20 -0
  11. data/lib/rbitter.rb +86 -0
  12. data/lib/rbitter/arcserver.rb +130 -0
  13. data/lib/rbitter/console.rb +93 -0
  14. data/lib/rbitter/default/config_json.rb +37 -0
  15. data/lib/rbitter/dlthread.rb +63 -0
  16. data/lib/rbitter/env.rb +62 -0
  17. data/lib/rbitter/libtwitter_connection_override.rb +46 -0
  18. data/lib/rbitter/records.rb +121 -0
  19. data/lib/rbitter/records_migrate/.keep +0 -0
  20. data/lib/rbitter/records_migrate/20150327_add_index.rb +12 -0
  21. data/lib/rbitter/records_migrate/20150504_add_replyto_column.rb +12 -0
  22. data/lib/rbitter/streaming.rb +105 -0
  23. data/lib/rbitter/version.rb +20 -0
  24. data/lib/rbitter/xmlrpc.rb +4 -0
  25. data/lib/rbitter/xmlrpcd/base.rb +25 -0
  26. data/lib/rbitter/xmlrpcd/rpchandles.rb +12 -0
  27. data/lib/rbitter/xmlrpcd/xmlrpc_auth_server.rb +83 -0
  28. data/lib/rbitter/xmlrpcd/xmlrpcd.rb +69 -0
  29. data/rbitter.gemspec +46 -0
  30. data/spec/config/.keep +0 -0
  31. data/spec/config/default.json +33 -0
  32. data/spec/rbitter/arcserver_spec.rb +30 -0
  33. data/spec/rbitter/console_spec.rb +9 -0
  34. data/spec/rbitter/default/config_json_spec.rb +3 -0
  35. data/spec/rbitter/dlthread_spec.rb +8 -0
  36. data/spec/rbitter/env_spec.rb +62 -0
  37. data/spec/rbitter/libtwitter_connection_override_spec.rb +8 -0
  38. data/spec/rbitter/records_spec.rb +13 -0
  39. data/spec/rbitter/streaming_spec.rb +9 -0
  40. data/spec/rbitter/version_spec.rb +8 -0
  41. data/spec/rbitter/xmlrpc_spec.rb +8 -0
  42. data/spec/rbitter/xmlrpcd/base_spec.rb +29 -0
  43. data/spec/rbitter/xmlrpcd/rpchandles_spec.rb +10 -0
  44. data/spec/rbitter/xmlrpcd/xmlrpc_auth_server_spec.rb +8 -0
  45. data/spec/rbitter/xmlrpcd/xmlrpcd_spec.rb +9 -0
  46. data/spec/rbitter_spec.rb +42 -0
  47. data/spec/sample_data/.keep +0 -0
  48. data/spec/spec_helper.rb +39 -0
  49. metadata +265 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 157a4cd2b13330fa06547688fc8cce5d22c30670
4
+ data.tar.gz: d12d38c95d8fd84047cb6b3ee2805dde1d0cd7af
5
+ SHA512:
6
+ metadata.gz: fbd300e20e5fdf8e711c3fdb38552d144552f7e84898a3274363de2267e9643dca13ddf888c1b8163b384c67de959839f00acc08db27568cdb962a280ffbf559
7
+ data.tar.gz: 2095fe34daf61fa83bfaa6fd1d276a24bf0e917591adbb0ea78c08788a8428fb4fa00200222236cadf3793b72beca9c5b00a05e63d27c1b25f94ad8e6d1d6d8b
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /build/
11
+ /vendor/
12
+ *.bundle
13
+ *.so
14
+ *.o
15
+ *.a
16
+ mkmf.log
17
+ *.gem
18
+ *.json
19
+ *.sqlite
20
+ .rbitter
21
+ .rbitter/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.1.0
5
+ - 2.2.0
6
+ - jruby-19mode
7
+ - jruby-head
8
+ - rbx-2
9
+
10
+ env: LANG="en_US.UTF-8" LC_ALL="en_US.UTF-8"
11
+
12
+ matrix:
13
+ allow_failures:
14
+ - rvm: ruby-head
15
+ - rvm: rbx-2
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ group :test do
4
+ gem 'rspec', '~>3.0'
5
+ gem 'simplecov', :require => false, :group => :test
6
+ gem 'coveralls', :require => false
7
+ end
8
+
9
+ gem "bundler"
10
+ gem 'jruby-openssl', platforms: :jruby
11
+
12
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Nidev Plontra
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Rbitter #
2
+ [![Build Status](https://travis-ci.org/nidev/rbitter.svg?branch=master)](https://travis-ci.org/nidev/rbitter)
3
+ [![Gem Version](https://badge.fury.io/rb/rbitter.svg)](http://badge.fury.io/rb/rbitter)
4
+ [![Coverage Status](https://coveralls.io/repos/nidev/rbitter/badge.svg?branch=master)](https://coveralls.io/r/nidev/rbitter?branch=master)
5
+
6
+ Rbitter is a Twitter streaming client specialized in tweet archiving with remote access via XMLRPC, which is written in Ruby.
7
+
8
+ You can save all tweets appeared on your home timeline and watch them later.
9
+
10
+ ## Requirements ##
11
+ Rbitter is tested under [MRI](https://www.ruby-lang.org), [JRuby](http://jruby.org) and [Rubinius](http://rubini.us). So you can choose one of these implementations.
12
+
13
+ It can run under both Windows and Linux.
14
+
15
+ Gem dependencies will be installed during installation of this gem.
16
+
17
+ * Ruby 1.9.3 or above
18
+ * Sqlite3
19
+ * Mysql(MariaDB)
20
+
21
+ ## Configuration ##
22
+ You can simply manipulate default configuration file by:
23
+
24
+ ```bash
25
+ $ rbitter configure
26
+ ```
27
+
28
+ Put your customized config.json to one of below locations.
29
+
30
+ 1. ./config.json (current folder)
31
+ 2. ./.rbitter/config.json (current folder)
32
+
33
+ ## Set up and run ##
34
+ With config.json,
35
+
36
+ 1. Get Twitter token and copy them properly.
37
+ 2. Choose preferred ActiveRecord backend.
38
+ 3. Modify default location where Twitter images are downloaded.
39
+ 4. Configure XMLRPC server
40
+ 5. Start by typing:
41
+
42
+ ```bash
43
+ $ rbitter serve
44
+ ```
45
+ ## XMLRPC API ##
46
+
47
+ See XMLRPC.md
48
+
49
+ ## TODO ##
50
+ * Streaming Client
51
+ * Saving JSON dump
52
+ * XMLRPC
53
+ * Receiving direct messages
54
+
55
+ ## Issue report or feature request ##
56
+ It's recommended to open an issue even it seemed too small. A small flaw may result in instability or bad situation. So every feature requests/bug reports are welcomed.
57
+
58
+ Please attach stack trace, Ruby version, Rbitter version, and detail description.
59
+
60
+ If you installed from [RubyGems], please report with Git tag. Git tag is your gem version.
61
+
62
+ [RubyGems]: https://rubygems.org
63
+
64
+ ## Application Versioning ##
65
+ Rbitter follows [Sementic Versioning 2.0](http://semver.org/spec/v2.0.0.html).
66
+
67
+ ## Disclaimer ##
68
+ Rbitter is intended for personal usage. Archived data should not be shared over Internet. Please keep them secure and safe, and protect privacy.
69
+
70
+ Using sqlite3, please set permission to 0700 so that other users can not read your database file. Using mysql2, please take care of DB access privilege.
71
+
72
+ Rbitter is not responsible for integrity of data. That is, Some tweets will be dropped accidently due to Twitter API problems or your network problems. The application does its best to recover from those problems. If you find Rbitter couldn't recover even after they're resolved, please make an issue report.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :basic_test => :spec
8
+
data/XMLRPC.md ADDED
@@ -0,0 +1,19 @@
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.
data/bin/rbitter ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rbitter"
4
+
5
+ Rbitter.rbitter_header
6
+
7
+ if ARGV.length < 1 || (not Rbitter::BOOTSTRAP_ARGS.include?(ARGV[0]))
8
+ Rbitter.rbitter_help_msg
9
+ exit -1
10
+ else
11
+ Rbitter.bootstrap(ARGV)
12
+
13
+ if ARGV[0] == "configure"
14
+ puts "Writing config.json done"
15
+ puts "You can put config.json one of these locations:"
16
+ puts "[1] config.json (current folder)"
17
+ puts "[2] .rbitter/config.json (current folder)"
18
+ end
19
+ end
20
+
data/lib/rbitter.rb ADDED
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+ #
3
+
4
+ require "rbitter/version"
5
+ require "rbitter/arcserver"
6
+ require "rbitter/env"
7
+ require "rbitter/console"
8
+ require "rbitter/xmlrpc"
9
+
10
+ module Rbitter
11
+ BOOTSTRAP_ARGS = ['configure', 'console', 'help', 'logs', 'serve']
12
+
13
+ def self.rbitter_header
14
+ puts "Rbitter #{VERSION} on #{RUBY_VERSION} (#{RUBY_PLATFORM})"
15
+ end
16
+
17
+ def self.rbitter_help_msg
18
+ puts "Rbitter is a Twitter streaming archiver, with XMLRPC access."
19
+ puts "-------"
20
+ puts "Usage: rbitter (application-mode)"
21
+ puts "application-mode's are:"
22
+ puts "|- serve : Launch Rbitter full system (Streaming + Database + XMLRPC)"
23
+ puts "|- console : Launch console application utilizing XMLRPC"
24
+ puts "|- configure: Write default configuration file 'config.json' in current folder"
25
+ puts "|- help : Show this message"
26
+ puts "`- logs : Show Rbitter internal logs"
27
+ end
28
+
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
+ def self.bootstrap_configs
53
+ require "rbitter/default/config_json"
54
+
55
+ open(File.join(Dir.pwd, "config.json"), "w") { |io|
56
+ io.write(DEFAULT_CONFIG_JSON)
57
+ }
58
+ end
59
+
60
+ def self.bootstrap args=[]
61
+ return nil if args.length < 1
62
+
63
+ if args[0] == "serve"
64
+ prebootstrap
65
+
66
+ Rbitter.config_initialize
67
+
68
+ archive_server = Rbitter::ArcServer.new
69
+ archive_server.main_loop
70
+ elsif args[0] == "help"
71
+ rbitter_help_msg
72
+ elsif args[0] == "configure"
73
+ bootstrap_configs
74
+ elsif args[0] == "console"
75
+ Rbitter.config_initialize
76
+
77
+ con = Rbitter::Console.new
78
+ con.start
79
+ elsif args[0] == "logs"
80
+ # show log in stdout
81
+ puts "Log buffer feature is in heavy development. Sorry."
82
+ else
83
+ fail StandardError, "Invalid bootstrap parameter: #{args[0]}"
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,130 @@
1
+ # encoding: utf-8
2
+
3
+ require "json"
4
+ require "date"
5
+ require "twitter"
6
+ require "resolv"
7
+
8
+ require "rbitter/records"
9
+ require "rbitter/streaming"
10
+ require "rbitter/dlthread"
11
+ require "rbitter/xmlrpc"
12
+
13
+ module Rbitter
14
+ class ArcServer
15
+ LOG_NORMAL = 0
16
+ LOG_INIT = 1
17
+ LOG_HALT = 2
18
+
19
+ def initialize(xmlrpcd_class = Rbitter::RPCServer)
20
+ @xmlrpcd_class = xmlrpcd_class
21
+
22
+ ARSupport.connect_database
23
+
24
+ if not ARSupport.prepared?
25
+ puts "Initiate database table..."
26
+ if Rbitter['activerecord'] == 'mysql2'
27
+ ARSupport.prepare "DEFAULT CHARSET=utf8mb4"
28
+ else
29
+ ARSupport.prepare
30
+ end
31
+ end
32
+
33
+ ARSupport.update_database_scheme
34
+
35
+ @dt = DLThread.new(
36
+ Rbitter['media_downloader']['download_dir'],
37
+ Rbitter['media_downloader']['large_image'])
38
+ end
39
+
40
+ def xmlrpcd_start
41
+ if Rbitter['xmlrpc']['enable']
42
+ @rpc_service = Thread.new {
43
+ rpc_server = @xmlrpcd_class.new(Rbitter['xmlrpc']['bind_host'], Rbitter['xmlrpc']['bind_port'])
44
+ rpc_server.main_loop
45
+ }
46
+ else
47
+ @rpc_service = nil
48
+ end
49
+ end
50
+
51
+ def xmlrpcd_stop
52
+ unless @rpc_service.nil?
53
+ if @rpc_service.alive?
54
+ puts "Finishing RPCServer (impl: #{@xmlrpcd_class})"
55
+ @rpc_service.terminate
56
+ @rpc_service.join
57
+ @rpc_service = nil
58
+ end
59
+ end
60
+ end
61
+
62
+ def mark(code, message)
63
+ Record.create({:marker => code,
64
+ :marker_msg => message,
65
+ :userid => nil,
66
+ :username => nil,
67
+ :tweetid => nil,
68
+ :replyto => nil,
69
+ :tweet => nil,
70
+ :date => ARSupport.any_to_datestring(DateTime.now),
71
+ :rt_count => 0,
72
+ :fav_count => 0})
73
+ end
74
+
75
+ def write_init_marker
76
+ mark(LOG_INIT, "Archiving service started")
77
+ end
78
+
79
+ def write_halt_marker
80
+ mark(LOG_HALT, "Archiving service halted")
81
+ end
82
+
83
+ def main_loop(streaming_adapter = Rbitter::StreamClient)
84
+ xmlrpcd_start if Rbitter['xmlrpc']['enable']
85
+
86
+ begin
87
+ write_init_marker
88
+
89
+ streaming_adapter.new(Rbitter['twitter'].dup).run { |a|
90
+ @dt << a['media_urls']
91
+
92
+ record = Record.find_or_initialize_by(tweetid: a['tweetid'])
93
+ record.update({:marker => 0,
94
+ :marker_msg => "normal",
95
+ :userid => a['userid'],
96
+ :username => a['screen_name'],
97
+ :tweetid => a['tweetid'],
98
+ :replyto => a['replyto'],
99
+ :tweet => a['tweet'],
100
+ :date => a['date'],
101
+ :rt_count => a['rt_count'],
102
+ :fav_count => a['fav_count']})
103
+
104
+ record.save
105
+ }
106
+ rescue Interrupt => e
107
+ puts ""
108
+ puts "Interrupted..."
109
+ rescue Twitter::Error::Unauthorized => e
110
+ warn "Twitter access unauthorized:"
111
+ warn " Possible solutions"
112
+ warn " 1. Configure Twitter token on config.json"
113
+ warn " 2. Check system time (Time is important on authentication)"
114
+ 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
119
+ rescue Twitter::Error => e
120
+ warn "Twitter Error: #{e.inspect}"
121
+ warn "Main loop of ArcServer halted."
122
+ ensure
123
+ xmlrpcd_stop if Rbitter['xmlrpc']['enable']
124
+ @dt.job_cleanup
125
+
126
+ write_halt_marker
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +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
+