spider-gazelle 3.0.5 → 3.0.6
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/spider-gazelle.rb +6 -10
- data/lib/spider-gazelle/logger.rb +6 -21
- data/lib/spider-gazelle/reactor.rb +10 -9
- data/lib/spider-gazelle/signaller.rb +6 -5
- data/lib/spider-gazelle/spider.rb +1 -1
- data/lib/spider-gazelle/upgrades/websocket.rb +70 -79
- data/lib/spider-gazelle/version.rb +1 -1
- 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: 49d9e0d9dee57cc23287f2155e6ebe81137e3f15
|
4
|
+
data.tar.gz: 385f9ee18cdc18dab2b1de1f34b689968c617e8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 932d6770571115d8e01d8e039725222929e7da5800be5d3ec9730505e97e1f8d153a76dfab4bbfb8ce8deea47993deb7d5a1797fabb7d869e5349c512108b6f7
|
7
|
+
data.tar.gz: 3b33aa02ef5fad6b922ef577e22c3b209cd6f2db336f85d74c666f75cc38574dec6db3ae7b76ce2ab1bd50b7af33fdbdc8d26893943f0e1982e3bb3303fff102
|
data/lib/spider-gazelle.rb
CHANGED
@@ -73,25 +73,21 @@ module SpiderGazelle
|
|
73
73
|
# ---------------------------------------
|
74
74
|
def launch_spider(args)
|
75
75
|
require 'securerandom'
|
76
|
-
require 'thread'
|
77
76
|
|
78
77
|
@password ||= SecureRandom.hex
|
79
|
-
#cmd = "#{EXEC_NAME} -s #{@password} #{Shellwords.join(args)}"
|
80
|
-
cmd = [EXEC_NAME, '-s', @password] + args
|
81
78
|
|
82
|
-
|
83
|
-
result = system(*cmd)
|
79
|
+
#cmd = "#{EXEC_NAME} -s #{@password} #{Shellwords.join(args)}"
|
84
80
|
|
85
|
-
|
86
|
-
|
87
|
-
|
81
|
+
thread = Reactor.instance.thread
|
82
|
+
spider = thread.spawn(EXEC_NAME, args: (['-s', @password] + args), mode: :inherit)
|
83
|
+
spider.finally do
|
84
|
+
signaller = ::SpiderGazelle::Signaller.instance
|
85
|
+
signaller.panic!('Unexpected spider exit') unless signaller.shutting_down
|
88
86
|
end
|
89
87
|
end
|
90
88
|
|
91
89
|
# This is called when a spider process starts
|
92
90
|
def start_spider(signaller, logger, options)
|
93
|
-
logger.set_client signaller.pipe unless options[0][:isolate]
|
94
|
-
|
95
91
|
require 'spider-gazelle/spider'
|
96
92
|
Spider.instance.run!(options)
|
97
93
|
end
|
@@ -5,7 +5,7 @@ require 'libuv'
|
|
5
5
|
module SpiderGazelle
|
6
6
|
class Logger
|
7
7
|
include Singleton
|
8
|
-
attr_reader :level, :thread, :
|
8
|
+
attr_reader :level, :thread, :stdout
|
9
9
|
attr_accessor :formatter
|
10
10
|
|
11
11
|
|
@@ -22,19 +22,14 @@ module SpiderGazelle
|
|
22
22
|
|
23
23
|
def initialize
|
24
24
|
@thread = ::Libuv::Reactor.default
|
25
|
+
@stdout = @thread.pipe
|
26
|
+
@stdout.open(1)
|
25
27
|
@level = DEFAULT_LEVEL
|
26
|
-
@write = method(:server_write)
|
27
28
|
end
|
28
29
|
|
29
30
|
|
30
31
|
def self.log(data)
|
31
|
-
Logger.instance.
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
|
-
def set_client(uv_io)
|
36
|
-
@pipe = uv_io
|
37
|
-
@write = method(:client_write)
|
32
|
+
Logger.instance.stdout.write(data)
|
38
33
|
end
|
39
34
|
|
40
35
|
def level=(level)
|
@@ -83,7 +78,7 @@ module SpiderGazelle
|
|
83
78
|
def verbose(msg = nil)
|
84
79
|
if @verbose
|
85
80
|
msg = yield if block_given?
|
86
|
-
@write
|
81
|
+
@stdout.write ">> #{msg}\n"
|
87
82
|
end
|
88
83
|
end
|
89
84
|
|
@@ -95,11 +90,6 @@ module SpiderGazelle
|
|
95
90
|
error(message)
|
96
91
|
end
|
97
92
|
|
98
|
-
# NOTE:: should only be called on reactor thread
|
99
|
-
def server_write(msg)
|
100
|
-
STDOUT.write msg
|
101
|
-
end
|
102
|
-
|
103
93
|
|
104
94
|
protected
|
105
95
|
|
@@ -107,13 +97,8 @@ module SpiderGazelle
|
|
107
97
|
def log(level, msg)
|
108
98
|
output = "[#{level}] #{msg}\n"
|
109
99
|
@thread.schedule do
|
110
|
-
@write
|
100
|
+
@stdout.write output
|
111
101
|
end
|
112
102
|
end
|
113
|
-
|
114
|
-
# NOTE:: should only be called on reactor thread
|
115
|
-
def client_write(msg)
|
116
|
-
@pipe.write "\x02Logger log #{msg}\x03"
|
117
|
-
end
|
118
103
|
end
|
119
104
|
end
|
@@ -38,16 +38,17 @@ module SpiderGazelle
|
|
38
38
|
end
|
39
39
|
|
40
40
|
@thread.schedule do
|
41
|
-
|
42
|
-
|
41
|
+
if not @shutdown_called
|
42
|
+
@shutdown_called = true
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
# Signaller will manage the shutdown of the gazelles
|
45
|
+
signaller = Signaller.instance.shutdown
|
46
|
+
signaller.finally do
|
47
|
+
@thread.stop
|
48
|
+
# New line on exit to avoid any ctrl-c characters
|
49
|
+
# We check for pipe as we only want the master process to print this
|
50
|
+
puts "\nSpider-Gazelle leaps through the veldt\n"
|
51
|
+
end
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
@@ -8,7 +8,7 @@ module SpiderGazelle
|
|
8
8
|
include Singleton
|
9
9
|
|
10
10
|
|
11
|
-
attr_reader :thread, :pipe
|
11
|
+
attr_reader :thread, :pipe, :is_connected, :shutting_down
|
12
12
|
attr_accessor :gazelle
|
13
13
|
|
14
14
|
|
@@ -19,7 +19,8 @@ module SpiderGazelle
|
|
19
19
|
# This is used to check if an instance of spider-gazelle is already running
|
20
20
|
@is_master = false
|
21
21
|
@is_client = false
|
22
|
-
@is_connected
|
22
|
+
@is_connected = false
|
23
|
+
@shutting_down = false
|
23
24
|
@client_check = @thread.defer
|
24
25
|
@validated = [] # Set requires more processing
|
25
26
|
@validating = {}
|
@@ -42,6 +43,7 @@ module SpiderGazelle
|
|
42
43
|
|
43
44
|
def shutdown
|
44
45
|
defer = @thread.defer
|
46
|
+
@shutting_down = true
|
45
47
|
|
46
48
|
# Close the SIGNAL_SERVER pipe
|
47
49
|
@pipe.close if @is_connected
|
@@ -115,7 +117,6 @@ module SpiderGazelle
|
|
115
117
|
@pipe.finally do
|
116
118
|
if @is_client
|
117
119
|
@is_connected = false
|
118
|
-
panic!(nil)
|
119
120
|
else
|
120
121
|
# Assume the role of master
|
121
122
|
become_sg_master
|
@@ -154,7 +155,7 @@ module SpiderGazelle
|
|
154
155
|
# If all the process connections are gone then we want to shutdown
|
155
156
|
# This should never happen under normal conditions
|
156
157
|
if @validated.length == 0
|
157
|
-
Reactor.instance.shutdown
|
158
|
+
Reactor.instance.shutdown unless @shutting_down
|
158
159
|
end
|
159
160
|
end
|
160
161
|
|
@@ -174,7 +175,7 @@ module SpiderGazelle
|
|
174
175
|
#@logger.error "Master pipe went missing: #{reason}"
|
175
176
|
# Server most likely exited
|
176
177
|
# We'll shutdown here
|
177
|
-
STDERR.puts "\n\npanic! #{reason.inspect}\n\n\n"
|
178
|
+
STDERR.puts "\n\npanic! #{reason.inspect}\n#{caller.join("\n")}\n\n\n"
|
178
179
|
STDERR.flush
|
179
180
|
Reactor.instance.shutdown
|
180
181
|
end
|
@@ -101,7 +101,7 @@ module SpiderGazelle
|
|
101
101
|
def shutdown(finished)
|
102
102
|
@shutdown_defer = finished
|
103
103
|
|
104
|
-
@logger.verbose { "Spider Pid: #{Process.pid} shutting down" }
|
104
|
+
@logger.verbose { "Spider Pid: #{Process.pid} shutting down (loaded #{@loaded})" }
|
105
105
|
|
106
106
|
if @loaded
|
107
107
|
perform_shutdown
|
@@ -3,104 +3,95 @@
|
|
3
3
|
require 'websocket/driver'
|
4
4
|
require 'forwardable'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader :env, :url, :reactor, :socket
|
6
|
+
class SpiderGazelle::Websocket < ::Libuv::Q::DeferredPromise
|
7
|
+
attr_reader :env, :url, :reactor, :socket
|
9
8
|
|
9
|
+
extend ::Forwardable
|
10
|
+
def_delegators :@driver, :start, :ping, :protocol, :ready_state, :set_header, :state, :close
|
11
|
+
def_delegators :@socket, :write, :peername
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
REQUEST_URI= 'REQUEST_URI'
|
14
|
-
HTTPS = 'https'
|
13
|
+
def initialize(tcp, env)
|
14
|
+
@socket, @env = tcp, env
|
15
15
|
|
16
|
+
# Initialise the promise
|
17
|
+
super tcp.reactor, tcp.reactor.defer
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
scheme = env['rack.url_scheme'] == 'https' ? 'wss://' : 'ws://'
|
20
|
+
@url = scheme + env['HTTP_HOST'] + env['REQUEST_URI']
|
21
|
+
@driver = ::WebSocket::Driver.rack self
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
+
# Pass data from the socket to the driver
|
24
|
+
@socket.progress &method(:socket_read)
|
25
|
+
@socket.finally &method(:socket_close)
|
23
26
|
|
24
|
-
# Initialise the promise
|
25
|
-
super tcp.reactor, tcp.reactor.defer
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@socket.finally &method(:socket_close)
|
34
|
-
|
35
|
-
|
36
|
-
# Driver has indicated that it is closing
|
37
|
-
# We'll close the socket after writing any remaining data
|
38
|
-
@driver.on :close, &method(:on_close)
|
39
|
-
@driver.on :message, &method(:on_message)
|
40
|
-
@driver.on :error, &method(:on_error)
|
41
|
-
end
|
28
|
+
# Driver has indicated that it is closing
|
29
|
+
# We'll close the socket after writing any remaining data
|
30
|
+
@driver.on :close, &method(:on_close)
|
31
|
+
@driver.on :message, &method(:on_message)
|
32
|
+
@driver.on :error, &method(:on_error)
|
33
|
+
end
|
42
34
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
35
|
+
# Write some text to the websocket connection
|
36
|
+
#
|
37
|
+
# @param string [String] a string of data to be sent to the far end
|
38
|
+
def text(string)
|
39
|
+
@reactor.schedule { @driver.text(string.to_s) }
|
40
|
+
end
|
49
41
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
# Write some binary data to the websocket connection
|
43
|
+
#
|
44
|
+
# @param array [Array] an array of bytes to be sent to the far end
|
45
|
+
def binary(array)
|
46
|
+
@reactor.schedule { @driver.binary(array.to_a) }
|
47
|
+
end
|
56
48
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
49
|
+
# Used to define a callback when data is received from the client
|
50
|
+
#
|
51
|
+
# @param callback [Proc] the callback to be called when data is received
|
52
|
+
def progress(callback = nil, &blk)
|
53
|
+
@progress = callback || blk
|
54
|
+
end
|
63
55
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
56
|
+
# Used to define a callback when the websocket connection is established
|
57
|
+
# Data sent before this callback is buffered.
|
58
|
+
#
|
59
|
+
# @param callback [Proc] the callback to be triggered on establishment
|
60
|
+
def on_open(callback = nil, &blk)
|
61
|
+
callback ||= blk
|
62
|
+
@driver.on :open, &callback
|
63
|
+
end
|
72
64
|
|
73
|
-
|
65
|
+
protected
|
74
66
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
67
|
+
def socket_read(data, tcp)
|
68
|
+
begin
|
69
|
+
@driver.parse data
|
70
|
+
rescue => e
|
71
|
+
# Prevent hanging sockets
|
72
|
+
@socket.close
|
73
|
+
raise e
|
83
74
|
end
|
75
|
+
end
|
84
76
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
77
|
+
def socket_close
|
78
|
+
if @shutdown_called.nil?
|
79
|
+
@defer.reject WebSocket::Driver::CloseEvent.new(1006, 'connection was closed unexpectedly')
|
89
80
|
end
|
81
|
+
end
|
90
82
|
|
91
83
|
|
92
|
-
|
93
|
-
|
94
|
-
|
84
|
+
def on_message(event)
|
85
|
+
@progress.call(event.data, self) unless @progress.nil?
|
86
|
+
end
|
95
87
|
|
96
|
-
|
97
|
-
|
98
|
-
|
88
|
+
def on_error(event)
|
89
|
+
@defer.reject event
|
90
|
+
end
|
99
91
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
92
|
+
def on_close(event)
|
93
|
+
@shutdown_called = true
|
94
|
+
@socket.shutdown
|
95
|
+
@defer.resolve event
|
105
96
|
end
|
106
97
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spider-gazelle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen von Takach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-parser
|
@@ -189,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
189
|
version: '0'
|
190
190
|
requirements: []
|
191
191
|
rubyforge_project:
|
192
|
-
rubygems_version: 2.6.
|
192
|
+
rubygems_version: 2.6.12
|
193
193
|
signing_key:
|
194
194
|
specification_version: 4
|
195
195
|
summary: A fast, parallel and concurrent web server for ruby
|