proxy_daemon 0.1.3 → 0.1.5
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 +4 -4
- data/lib/proxy_daemon/daemon.rb +70 -46
- data/lib/proxy_daemon/version.rb +1 -1
- data/lib/proxy_daemon/worker.rb +41 -33
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b3331057afa6180824de6caef0c7850ce2ad626
|
4
|
+
data.tar.gz: 067c6efd89f48be51d25f8318ea66fe5c44a553f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 375d890481795fbeca35f98eaaf0dcfb1648a2fc21993a83be077aa195146881a16669d5845f62555ec0e0caf2772010e93b7944f7eba2135d67515433dbe9d2
|
7
|
+
data.tar.gz: 7e87ce478643d0261289738aeb021c03865012e28f3270c28e2b5379344ad5041c44ce5670ed9dbc3c410e35a32830d580116ce10d4710ddc73212dace5bc7c0
|
data/lib/proxy_daemon/daemon.rb
CHANGED
@@ -6,62 +6,79 @@ require 'colorize'
|
|
6
6
|
module ProxyDaemon
|
7
7
|
class Daemon
|
8
8
|
attr_accessor :list
|
9
|
-
|
10
|
-
def initialize(
|
11
|
-
@script =
|
12
|
-
|
9
|
+
|
10
|
+
def initialize(script_or_parser, options = nil)
|
11
|
+
if script_or_parser.is_a? String then @script = script_or_parser
|
12
|
+
else
|
13
|
+
@script = '-'
|
14
|
+
|
15
|
+
if script_or_parser.is_a? Hash then options = script_or_parser
|
16
|
+
else @parser = script_or_parser end
|
17
|
+
end
|
18
|
+
|
19
|
+
@proxies = ((options[:proxies].map { |proxy| proxy.gsub /\s+/, ' ' }) || [])#.shuffle
|
13
20
|
@urls = options[:urls] || []
|
14
|
-
@
|
21
|
+
@worker_processes = (options[:worker_processes] || 10)
|
15
22
|
@tries = options[:tries] || 4
|
16
|
-
|
23
|
+
|
17
24
|
@threads = []
|
18
25
|
@list = {}
|
19
26
|
@semaphore = Mutex.new
|
20
27
|
end
|
21
|
-
|
22
|
-
def command(cmd, pipe,
|
28
|
+
|
29
|
+
def command(cmd, pipe, params = {})
|
30
|
+
command = {command: cmd}.merge(params)
|
31
|
+
|
23
32
|
Thread.current[:command] = cmd
|
24
|
-
pipe.
|
33
|
+
pipe.puts(command.to_json)
|
25
34
|
end
|
26
|
-
|
35
|
+
|
27
36
|
def listen(pipe, try = 0)
|
28
|
-
|
29
|
-
|
37
|
+
packet = JSON.parse((pipe.gets || '').strip)
|
38
|
+
raise "Empty answer from worker process" if packet.empty?
|
39
|
+
answer = packet['answer']
|
40
|
+
raise "Process: '#{answer}'" if answer == 'timeout' || answer == 'error'
|
41
|
+
|
30
42
|
if answer == 'proxy'
|
31
43
|
raise "Broken url: #{Thread.current[:url]}" if try > @tries
|
32
|
-
|
44
|
+
|
33
45
|
proxy = getProxy
|
46
|
+
log "Answer: #{answer}, data: #{packet['data']}".yellow, pipe
|
34
47
|
log "Choosing new proxy: #{(proxy || 'nil').yellow}", pipe
|
35
|
-
command :proxy, pipe, proxy
|
36
|
-
command :url, pipe, Thread.current[:url]
|
48
|
+
command :proxy, pipe, proxy: proxy
|
49
|
+
# command :url, pipe, url: Thread.current[:url]
|
37
50
|
listen pipe, try+1
|
38
|
-
elsif answer
|
39
|
-
|
40
|
-
|
41
|
-
raise "Process: '#{answer}'"
|
42
|
-
elsif Thread.current[:command] == :url
|
43
|
-
if (buf = answer.match(/^set (.+?)[\s]*:[\s]*?(.+)$/i)); @list[buf[1]] = buf[2] end
|
44
|
-
log "Process: #{Thread.current[:url].cyan}: '#{answer.green}'", pipe
|
51
|
+
elsif answer == 'ok'
|
52
|
+
@semaphore.synchronize { @list.merge! packet['data'] } if packet.key? 'data'
|
53
|
+
log "Process: #{Thread.current[:url].cyan}: '#{answer.green}', data: #{packet['data'].to_json}", pipe
|
45
54
|
else
|
46
|
-
log "Answer: #{answer}".green, pipe
|
55
|
+
log "Answer: #{answer}, data: #{packet['data'].to_json}".green, pipe
|
47
56
|
end
|
48
57
|
end
|
49
|
-
|
58
|
+
|
50
59
|
def worker
|
51
60
|
IO.popen("#{@script}", 'r+') { |p|
|
52
61
|
if (@script == '-' && p.nil?) # child process
|
53
|
-
if @block.nil?
|
54
|
-
$stderr.
|
62
|
+
if @block.nil? && @parser.nil?
|
63
|
+
$stderr.syswrite "[#{Process.pid}]".magenta + ' The parser is undefined and block wasn\'t given for parsing the content'.red + "\n"
|
64
|
+
$stderr.flush
|
65
|
+
|
55
66
|
Kernel.exit!
|
56
67
|
end
|
57
68
|
|
58
|
-
|
59
|
-
|
69
|
+
if @parser
|
70
|
+
worker = ProxyDaemon::Worker.new(@parser, @parse_method)
|
71
|
+
worker.call
|
72
|
+
elsif @block
|
73
|
+
worker = ProxyDaemon::Worker.new
|
74
|
+
worker.call(&@block)
|
75
|
+
end
|
60
76
|
else
|
77
|
+
p.sync = true
|
61
78
|
proxy = getProxy
|
62
79
|
log "Starting loop with new proxy: ".green + "#{(proxy || 'nil').yellow}", p
|
63
|
-
command :proxy, p, proxy
|
64
|
-
|
80
|
+
command :proxy, p, proxy: proxy
|
81
|
+
|
65
82
|
begin
|
66
83
|
loop do
|
67
84
|
sleep(0.1)
|
@@ -74,41 +91,47 @@ module ProxyDaemon
|
|
74
91
|
else
|
75
92
|
log 'Urls count: ' + "#{@urls.length}".green + ", #{url.green}"
|
76
93
|
Thread.current[:url] = url
|
77
|
-
command :url, p, url
|
94
|
+
command :url, p, url: url
|
78
95
|
listen p
|
79
96
|
end
|
80
97
|
end
|
81
|
-
|
98
|
+
|
82
99
|
log "Finishing loop".green, p
|
83
100
|
rescue Exception => e
|
84
101
|
@semaphore.synchronize {
|
85
|
-
log "Exception in main:
|
102
|
+
log "Exception in main:".red + " '#{Thread.current[:url]}'".yellow + " #{e.message.red}".red + "\n#{e.backtrace.join("\n").red}\n", p
|
86
103
|
command :exit, p
|
87
104
|
#puts e.backtrace
|
88
105
|
}
|
89
106
|
end
|
90
107
|
end
|
91
108
|
}
|
92
|
-
|
109
|
+
|
93
110
|
if @urls.length > 0
|
94
111
|
# @threads << Thread.new(&(->{worker}))
|
95
112
|
# @threads.last.join
|
96
113
|
worker
|
97
114
|
end
|
98
115
|
end
|
99
|
-
|
100
|
-
def start(&block)
|
116
|
+
|
117
|
+
def start(options = nil, &block)
|
101
118
|
@block = block if block_given?
|
119
|
+
@parse_method = options[:parse] if options && options.key?(:parse)
|
120
|
+
worker_processes = [@worker_processes, @urls.count].min
|
102
121
|
|
103
122
|
begin
|
104
|
-
puts "[main] Starting " + "#{
|
105
|
-
|
123
|
+
puts "[main] Starting " + "#{worker_processes}".yellow + " workers:"
|
124
|
+
worker_processes.times { |i| @threads << Thread.new(&(->{worker})) }
|
106
125
|
@threads.each { |t| t.join }
|
107
126
|
rescue Interrupt => e
|
108
127
|
puts "[main] Interrupted by user".yellow
|
109
128
|
end
|
110
129
|
end
|
111
|
-
|
130
|
+
|
131
|
+
def add_urls(urls)
|
132
|
+
@semaphore.synchronize { @urls |= [*urls] }
|
133
|
+
end
|
134
|
+
|
112
135
|
private
|
113
136
|
def getProxy
|
114
137
|
proxy = String.new
|
@@ -119,24 +142,25 @@ module ProxyDaemon
|
|
119
142
|
|
120
143
|
proxy
|
121
144
|
end
|
122
|
-
|
145
|
+
|
123
146
|
def getUrl
|
124
147
|
url = String.new
|
125
148
|
@semaphore.synchronize { url = @urls.shift }
|
126
|
-
|
149
|
+
|
127
150
|
url
|
128
151
|
end
|
129
|
-
|
152
|
+
|
130
153
|
def finished(msg, pipe = 0)
|
131
154
|
unless @finished
|
132
155
|
@finished = true
|
133
156
|
@semaphore.synchronize { log msg, pipe }
|
134
157
|
end
|
135
158
|
end
|
136
|
-
|
159
|
+
|
137
160
|
def log(msg, pipe = nil)
|
138
|
-
unless pipe.nil? then
|
139
|
-
else
|
161
|
+
unless pipe.nil? then $stdout.syswrite "[#{pipe.pid}]".blue + " #{msg}\n"
|
162
|
+
else $stdout.syswrite "#{msg}\n" end
|
163
|
+
$stdout.flush
|
140
164
|
end
|
141
165
|
end
|
142
|
-
end
|
166
|
+
end
|
data/lib/proxy_daemon/version.rb
CHANGED
data/lib/proxy_daemon/worker.rb
CHANGED
@@ -6,18 +6,21 @@ require 'openssl'
|
|
6
6
|
module ProxyDaemon
|
7
7
|
class Worker
|
8
8
|
attr_accessor :url
|
9
|
-
|
10
|
-
def initialize
|
9
|
+
|
10
|
+
def initialize(parser = nil, parse_method = nil)
|
11
11
|
@client = Net::HTTP.Proxy(nil, nil)
|
12
|
+
@parser = parser
|
13
|
+
@parse_method = parse_method
|
12
14
|
@url = ''
|
13
15
|
end
|
14
|
-
|
16
|
+
|
15
17
|
def listen
|
16
18
|
begin
|
17
19
|
command = ''
|
18
20
|
Timeout::timeout(6) {
|
19
21
|
command = ($stdin.gets || String.new).strip
|
20
|
-
|
22
|
+
log ('Task: ' + command.to_s.yellow)
|
23
|
+
|
21
24
|
if command.empty?
|
22
25
|
log "Got empty answer from daemon, exiting...".yellow
|
23
26
|
raise Timeout::Error
|
@@ -27,13 +30,16 @@ module ProxyDaemon
|
|
27
30
|
answer 'timeout'
|
28
31
|
Kernel.exit!
|
29
32
|
end
|
30
|
-
|
33
|
+
|
31
34
|
command
|
32
35
|
end
|
33
|
-
|
34
|
-
def answer(
|
36
|
+
|
37
|
+
def answer(answer, data = nil)
|
35
38
|
begin
|
36
|
-
|
39
|
+
pack = {answer: answer}
|
40
|
+
pack[:data] = data if data
|
41
|
+
|
42
|
+
$stdout.puts pack.to_json
|
37
43
|
$stdout.flush
|
38
44
|
rescue Errno::EPIPE => e
|
39
45
|
log 'Broken pipe with daemon, exiting...'.yellow
|
@@ -42,7 +48,7 @@ module ProxyDaemon
|
|
42
48
|
log e.inspect.red
|
43
49
|
end
|
44
50
|
end
|
45
|
-
|
51
|
+
|
46
52
|
def process(url)
|
47
53
|
begin
|
48
54
|
uri = URI(url)
|
@@ -63,31 +69,30 @@ module ProxyDaemon
|
|
63
69
|
@page = http.request(req)
|
64
70
|
}
|
65
71
|
}
|
66
|
-
|
72
|
+
|
67
73
|
if (!@page.is_a?(Net::HTTPOK) || @page.body.empty?)
|
68
74
|
log @page
|
69
75
|
raise Net::HTTPBadResponse
|
70
76
|
end
|
71
|
-
|
77
|
+
|
72
78
|
res = parse(@page.body)
|
73
|
-
|
74
|
-
if !!res
|
75
|
-
|
76
|
-
else; answer('error') end
|
79
|
+
|
80
|
+
if !!res === res || res.nil? then answer(res ? 'ok' : 'error')
|
81
|
+
else answer('ok', res) end
|
77
82
|
rescue Timeout::Error, Errno::ETIMEDOUT, Errno::ECONNREFUSED,
|
78
83
|
Errno::EINVAL, Errno::ECONNRESET, Errno::ENETUNREACH, SocketError, EOFError,
|
79
|
-
TypeError, Net::HTTPExceptions, Net::HTTPBadResponse, OpenSSL::SSL::SSLError => e
|
80
|
-
log
|
84
|
+
TypeError, Zlib::BufError, Net::HTTPExceptions, Net::HTTPBadResponse, OpenSSL::SSL::SSLError => e
|
85
|
+
log 'proxy'.red + " in #{'process'.yellow}: #{e.inspect.red}"
|
81
86
|
answer 'proxy'
|
82
87
|
rescue Interrupt => e
|
83
88
|
log 'Interrupted by user, exiting...'.yellow
|
84
89
|
Kernel.exit!
|
85
90
|
rescue Exception => e
|
86
|
-
log "rescue in #{'process'.yellow}: #{e.inspect},\n#{e.backtrace.
|
91
|
+
log "rescue in #{'process'.yellow}: #{e.inspect},\n#{e.backtrace.join("\n").red}"
|
87
92
|
answer 'error'
|
88
93
|
end
|
89
94
|
end
|
90
|
-
|
95
|
+
|
91
96
|
def changeProxy(proxy)
|
92
97
|
if proxy == 'localhost' || proxy.nil? || (proxy = proxy.split(/\s+/)).length < 2
|
93
98
|
ENV['http_proxy'] = nil
|
@@ -95,42 +100,45 @@ module ProxyDaemon
|
|
95
100
|
ENV['http_proxy'] = "http://#{proxy[0]}:#{proxy[1]}"
|
96
101
|
end
|
97
102
|
end
|
98
|
-
|
103
|
+
|
99
104
|
def parse(body)
|
100
|
-
raise NotImplementedError if @block.nil?
|
105
|
+
raise NotImplementedError if @parser.nil? && @block.nil?
|
101
106
|
|
102
|
-
@block.call(self, body)
|
107
|
+
@block.call(self, body) if @block
|
108
|
+
@parser.send(:"parse_#{@parse_method}", self, body) if @parser
|
103
109
|
# instance_exec body, &@block
|
104
110
|
end
|
105
111
|
|
106
112
|
def call(&block)
|
113
|
+
$stdout.sync = true
|
107
114
|
@block = block if block_given?
|
108
115
|
proxy = nil
|
109
116
|
|
110
117
|
loop do
|
111
118
|
begin
|
112
|
-
task = listen
|
113
|
-
|
114
|
-
|
115
|
-
|
119
|
+
task = JSON.parse(listen)
|
120
|
+
|
121
|
+
case task['command']
|
122
|
+
when 'proxy'
|
123
|
+
proxy = task['proxy']
|
116
124
|
changeProxy(proxy)
|
117
|
-
|
118
|
-
|
125
|
+
process(@url) unless @url.empty?
|
126
|
+
when 'url'
|
127
|
+
@url = task['url']
|
119
128
|
process(@url)
|
120
|
-
when
|
129
|
+
when 'exit'
|
121
130
|
exit!
|
122
131
|
end
|
123
|
-
|
124
|
-
#$stderr.puts "[child #{Process.pid}]".magenta + ' Task: ' + task.to_s.yellow
|
125
132
|
rescue => e
|
126
133
|
log "rescue in #{'call'.yellow}: #{e.inspect.red}"
|
127
134
|
answer 'error'
|
128
135
|
end
|
129
136
|
end
|
130
137
|
end
|
131
|
-
|
138
|
+
|
132
139
|
def log(msg)
|
133
|
-
$stderr.
|
140
|
+
$stderr.syswrite "[child #{Process.pid}]".magenta + " #{msg}\n"
|
141
|
+
$stderr.flush
|
134
142
|
end
|
135
143
|
end
|
136
144
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: proxy_daemon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michail Volkov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -95,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
95
|
version: '0'
|
96
96
|
requirements: []
|
97
97
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.
|
98
|
+
rubygems_version: 2.6.4
|
99
99
|
signing_key:
|
100
100
|
specification_version: 4
|
101
101
|
summary: Simple daemon for grabbing sites via proxy servers.
|