rbitter 0.1.2-java
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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.travis.yml +15 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +8 -0
- data/XMLRPC.md +19 -0
- data/bin/rbitter +20 -0
- data/lib/rbitter.rb +86 -0
- data/lib/rbitter/arcserver.rb +130 -0
- data/lib/rbitter/console.rb +93 -0
- data/lib/rbitter/default/config_json.rb +37 -0
- data/lib/rbitter/dlthread.rb +63 -0
- data/lib/rbitter/env.rb +62 -0
- data/lib/rbitter/libtwitter_connection_override.rb +46 -0
- data/lib/rbitter/records.rb +121 -0
- data/lib/rbitter/records_migrate/.keep +0 -0
- data/lib/rbitter/records_migrate/20150327_add_index.rb +12 -0
- data/lib/rbitter/records_migrate/20150504_add_replyto_column.rb +12 -0
- data/lib/rbitter/streaming.rb +105 -0
- data/lib/rbitter/version.rb +20 -0
- data/lib/rbitter/xmlrpc.rb +4 -0
- data/lib/rbitter/xmlrpcd/base.rb +25 -0
- data/lib/rbitter/xmlrpcd/rpchandles.rb +12 -0
- data/lib/rbitter/xmlrpcd/xmlrpc_auth_server.rb +83 -0
- data/lib/rbitter/xmlrpcd/xmlrpcd.rb +69 -0
- data/rbitter.gemspec +46 -0
- data/spec/config/.keep +0 -0
- data/spec/config/default.json +33 -0
- data/spec/rbitter/arcserver_spec.rb +30 -0
- data/spec/rbitter/console_spec.rb +9 -0
- data/spec/rbitter/default/config_json_spec.rb +3 -0
- data/spec/rbitter/dlthread_spec.rb +8 -0
- data/spec/rbitter/env_spec.rb +62 -0
- data/spec/rbitter/libtwitter_connection_override_spec.rb +8 -0
- data/spec/rbitter/records_spec.rb +13 -0
- data/spec/rbitter/streaming_spec.rb +9 -0
- data/spec/rbitter/version_spec.rb +8 -0
- data/spec/rbitter/xmlrpc_spec.rb +8 -0
- data/spec/rbitter/xmlrpcd/base_spec.rb +29 -0
- data/spec/rbitter/xmlrpcd/rpchandles_spec.rb +10 -0
- data/spec/rbitter/xmlrpcd/xmlrpc_auth_server_spec.rb +8 -0
- data/spec/rbitter/xmlrpcd/xmlrpcd_spec.rb +9 -0
- data/spec/rbitter_spec.rb +42 -0
- data/spec/sample_data/.keep +0 -0
- data/spec/spec_helper.rb +39 -0
- metadata +265 -0
@@ -0,0 +1,20 @@
|
|
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
|
@@ -0,0 +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
|
25
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rbitter/xmlrpcd/rpchandles"
|
4
|
+
require "rbitter/xmlrpcd/base"
|
5
|
+
require "xmlrpc/server"
|
6
|
+
require "webrick"
|
7
|
+
|
8
|
+
module XMLRPC
|
9
|
+
class HTTPAuthXMLRPCServer < XMLRPC::WEBrickServlet
|
10
|
+
def extract_method(methodname, *args)
|
11
|
+
for name, obj in @handler
|
12
|
+
if obj.kind_of? Proc
|
13
|
+
next unless methodname == name
|
14
|
+
else
|
15
|
+
next unless methodname =~ /^#{name}(.+)$/
|
16
|
+
next unless obj.respond_to? $1
|
17
|
+
return obj.method($1)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def service(request, response)
|
24
|
+
# Taken from xmlrpc/server.rb
|
25
|
+
if @valid_ip
|
26
|
+
raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
|
27
|
+
end
|
28
|
+
|
29
|
+
if request.request_method != "POST"
|
30
|
+
raise WEBrick::HTTPStatus::MethodNotAllowed,
|
31
|
+
"unsupported method `#{request.request_method}'."
|
32
|
+
end
|
33
|
+
|
34
|
+
if parse_content_type(request['Content-type']).first != "text/xml"
|
35
|
+
raise WEBrick::HTTPStatus::BadRequest
|
36
|
+
end
|
37
|
+
|
38
|
+
length = (request['Content-length'] || 0).to_i
|
39
|
+
|
40
|
+
raise WEBrick::HTTPStatus::LengthRequired unless length > 0
|
41
|
+
|
42
|
+
data = request.body
|
43
|
+
|
44
|
+
if data.nil? or data.bytesize != length
|
45
|
+
raise WEBrick::HTTPStatus::BadRequest
|
46
|
+
end
|
47
|
+
|
48
|
+
# Originally, process(data) was here.
|
49
|
+
# We need to check whether a method requires authorization.
|
50
|
+
rpc_method_name, rpc_params = parser().parseMethodCall(data)
|
51
|
+
rpc_method = extract_method(rpc_method_name)
|
52
|
+
|
53
|
+
if RPCHandles.auth.nil?
|
54
|
+
resp = handle(rpc_method_name, *rpc_params)
|
55
|
+
else
|
56
|
+
if rpc_method.owner.ancestors.include?(RPCHandles::BaseHandle::Auth)
|
57
|
+
# Check cookie and check it's valid
|
58
|
+
if request.cookies.size == 1 \
|
59
|
+
and request.cookies[0].name == "auth_key" \
|
60
|
+
and RPCHandles.auth.include?(request.cookies[0].value)
|
61
|
+
resp = handle(rpc_method_name, *rpc_params)
|
62
|
+
else
|
63
|
+
# Permission required
|
64
|
+
raise WEBrick::HTTPStatus::Forbidden
|
65
|
+
end
|
66
|
+
elsif rpc_method.owner.ancestors.include?(RPCHandles::BaseHandle::NoAuth)
|
67
|
+
resp = handle(rpc_method_name, *rpc_params)
|
68
|
+
else
|
69
|
+
raise WEBrick::HTTPStatus::Forbidden
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if resp.nil? or resp.bytesize <= 0
|
74
|
+
raise WEBrick::HTTPStatus::InternalServerError
|
75
|
+
end
|
76
|
+
|
77
|
+
response.status = 200
|
78
|
+
response['Content-Length'] = resp.bytesize
|
79
|
+
response['Content-Type'] = "text/xml; charset=utf-8"
|
80
|
+
response.body = resp
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rbitter/xmlrpcd/rpchandles"
|
4
|
+
require "rbitter/xmlrpcd/xmlrpc_auth_server"
|
5
|
+
require "webrick"
|
6
|
+
|
7
|
+
module Rbitter
|
8
|
+
RPC_PREFIX="rbitter"
|
9
|
+
|
10
|
+
class RPCServer
|
11
|
+
def initialize bind_host, bind_port
|
12
|
+
@server = WEBrick::HTTPServer.new(:Port => bind_port.to_i, :BindAddress => bind_host.to_s, :MaxClients => 4, :Logger => WEBrick::Log.new($stdout))
|
13
|
+
@core = XMLRPC::HTTPAuthXMLRPCServer.new
|
14
|
+
@core.set_default_handler { |name, *args|
|
15
|
+
"NO_COMMAND: #{name} with args #{args.inspect}"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_all_handles
|
20
|
+
Rbitter["xmlrpc"]["handles"].each { |path|
|
21
|
+
puts "[xmlrpc] Scanning handles from (#{path})"
|
22
|
+
Dir.entries(path).each { |fname|
|
23
|
+
fname = File.join(path, fname)
|
24
|
+
if File.exist?(fname) and File.file?(fname)
|
25
|
+
if fname.match(/rh_\w+\.rb$/)
|
26
|
+
begin
|
27
|
+
load fname
|
28
|
+
rescue Exception => e
|
29
|
+
# stub
|
30
|
+
puts "Exception while loading #{fname}"
|
31
|
+
puts e.inspect
|
32
|
+
end
|
33
|
+
else
|
34
|
+
puts "Ignored: #{fname}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
puts "[xmlrpc] found #{RPCHandles.constants.length} constants."
|
41
|
+
RPCHandles.constants.each { |handler|
|
42
|
+
if RPCHandles.const_get(handler).is_a?(Class)
|
43
|
+
@core.add_handler(RPC_PREFIX, RPCHandles.const_get(handler).new)
|
44
|
+
end
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def main_loop
|
49
|
+
load_all_handles
|
50
|
+
|
51
|
+
@server.mount("/", @core)
|
52
|
+
@server.start
|
53
|
+
|
54
|
+
puts "[xmlrpc] XMLRPC started"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class DummyRPCServer
|
59
|
+
def initialize bind_host, bind_port; end
|
60
|
+
|
61
|
+
def load_all_handles; end
|
62
|
+
|
63
|
+
def main_loop
|
64
|
+
puts "[xmlrpc] DummyRPCServer started"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class NullRPCServer; end
|
69
|
+
end
|
data/rbitter.gemspec
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'rbitter/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "rbitter"
|
9
|
+
spec.version = Rbitter::VERSION
|
10
|
+
spec.authors = ["Nidev Plontra"]
|
11
|
+
spec.email = ["nidev.plontra@gmail.com"]
|
12
|
+
spec.summary = %q{Rbitter is a Twitter client specialized in archiving}
|
13
|
+
spec.description = %q{Rbitter archives all tweets appeared on user streaming using ActiveRecord. XMLRPC is used to serve archived tweets and useful features}
|
14
|
+
spec.homepage = "https://github.com/nidev/rbitter"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
|
23
|
+
spec.add_dependency 'twitter', '~> 5.14'
|
24
|
+
spec.add_dependency 'json', '~> 1.7'
|
25
|
+
spec.add_dependency 'ripl', '~> 0.7'
|
26
|
+
spec.add_dependency 'activerecord', '~> 4.0'
|
27
|
+
|
28
|
+
if RUBY_PLATFORM == 'java'
|
29
|
+
spec.platform = 'java'
|
30
|
+
|
31
|
+
spec.add_dependency 'activerecord-jdbc-adapter', '~> 1.3'
|
32
|
+
spec.add_dependency 'jdbc-sqlite3', '~> 3.8'
|
33
|
+
spec.add_dependency 'jdbc-mysql', '~> 5.1'
|
34
|
+
spec.add_dependency 'activerecord-jdbcsqlite3-adapter', '~> 1.3'
|
35
|
+
spec.add_dependency 'activerecord-jdbcmysql-adapter', '~> 1.3'
|
36
|
+
else
|
37
|
+
spec.platform = 'ruby'
|
38
|
+
|
39
|
+
spec.add_dependency 'sqlite3', '~> 1.3'
|
40
|
+
spec.add_dependency 'mysql2', '~> 0.3'
|
41
|
+
spec.add_dependency 'activerecord-mysql2-adapter', '~> 0.0.3'
|
42
|
+
end
|
43
|
+
|
44
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
45
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
46
|
+
end
|
data/spec/config/.keep
ADDED
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
{
|
2
|
+
"twitter": {
|
3
|
+
"consumer_key": "",
|
4
|
+
"consumer_secret": "",
|
5
|
+
"access_token": "",
|
6
|
+
"access_token_secret": ""
|
7
|
+
},
|
8
|
+
"activerecord": "sqlite3",
|
9
|
+
"sqlite3": {
|
10
|
+
"dbfile": "rbitter.sqlite"
|
11
|
+
},
|
12
|
+
"mysql2": {
|
13
|
+
"host": "localhost",
|
14
|
+
"port": 3306,
|
15
|
+
"dbname": "archive",
|
16
|
+
"username": "",
|
17
|
+
"password": ""
|
18
|
+
},
|
19
|
+
"media_downloader": {
|
20
|
+
"cacert_path": "/cacerts/cacert.pem",
|
21
|
+
"download_dir": "imgs/"
|
22
|
+
},
|
23
|
+
"xmlrpc": {
|
24
|
+
"enable": true,
|
25
|
+
"bind_host": "0.0.0.0",
|
26
|
+
"bind_port": 1400,
|
27
|
+
"auth": {
|
28
|
+
"username": "username",
|
29
|
+
"password": "password"
|
30
|
+
},
|
31
|
+
"handles": ["/path/to/handles"]
|
32
|
+
}
|
33
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rbitter/arcserver"
|
4
|
+
require "rbitter/streaming"
|
5
|
+
require "rbitter/xmlrpcd/xmlrpcd"
|
6
|
+
|
7
|
+
describe Rbitter::ArcServer do
|
8
|
+
it 'is presented' do
|
9
|
+
expect(Rbitter::ArcServer).to be_a(Class)
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'With dummy implementations, ' do
|
13
|
+
before(:all) do
|
14
|
+
Rbitter.bootstrap(['configure'])
|
15
|
+
expect(File.file?('config.json')).to be(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'successfully returns from main_loop' do
|
19
|
+
Rbitter.config_initialize
|
20
|
+
|
21
|
+
arcserver = Rbitter::ArcServer.new(Rbitter::DummyRPCServer)
|
22
|
+
arcserver.main_loop(Rbitter::DummyStreamClient)
|
23
|
+
end
|
24
|
+
|
25
|
+
after(:all) do
|
26
|
+
File.delete('config.json') if File.exist?('config.json')
|
27
|
+
File.delete('rbitter.sqlite') if File.exist?('rbitter.sqlite')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rbitter"
|
4
|
+
|
5
|
+
describe Rbitter do
|
6
|
+
it 'has env_reset function and clears Rbitter.env,' do
|
7
|
+
Rbitter.env_reset
|
8
|
+
expect(Rbitter.env).to be_a(Hash)
|
9
|
+
expect(Rbitter.env.length).to be(0)
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when config.json is not installed,' do
|
13
|
+
it 'fails on loading' do
|
14
|
+
expect{Rbitter.config_initialize}.to raise_error(Rbitter::ConfigFileError)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when path to config.json is invalid,' do
|
19
|
+
it 'fals on loading' do
|
20
|
+
expect{Rbitter.config_initialize("/silly/dummy/.")}.to raise_error(Rbitter::ConfigFileError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
context 'when default config.json is installed,' do
|
26
|
+
before(:all) do
|
27
|
+
Rbitter.bootstrap(['configure'])
|
28
|
+
expect(File.file?('config.json')).to be(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'loads configuration successfully with autodetection' do
|
32
|
+
expect{Rbitter.config_initialize}.to_not raise_error
|
33
|
+
expect(Rbitter.env.length > 0).to be(true)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'loads configuration successfully with given config.json path' do
|
37
|
+
expect{Rbitter.config_initialize('config.json')}.to_not raise_error
|
38
|
+
expect(Rbitter.env.length > 0).to be(true)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'checks that Rbitter.env returns Hash' do
|
42
|
+
expect{Rbitter.config_initialize}.to_not raise_error
|
43
|
+
expect(Rbitter.env).to be_a(Hash)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'checks that Rbitter[] works' do
|
47
|
+
expect{Rbitter.config_initialize}.to_not raise_error
|
48
|
+
expect(Rbitter["twitter"]).to be_a(Hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
after(:all) do
|
52
|
+
File.delete('config.json')
|
53
|
+
end
|
54
|
+
end
|
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
|
60
|
+
|
61
|
+
# TODO: Perform test with spec/config/default.json
|
62
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "rbitter/records"
|
3
|
+
|
4
|
+
describe Rbitter::Record do
|
5
|
+
# TODO: Perform test...
|
6
|
+
it 'has ActiveRecord class named Record' do
|
7
|
+
expect(Rbitter::Record).to be_a(Class)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'has supportive module of ActiveRecord' do
|
11
|
+
expect(ARSupport).to be_a(Module)
|
12
|
+
end
|
13
|
+
end
|