listen 2.10.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -46
- data/lib/listen.rb +19 -40
- data/lib/listen/adapter.rb +1 -3
- data/lib/listen/adapter/base.rb +66 -36
- data/lib/listen/adapter/config.rb +21 -0
- data/lib/listen/adapter/linux.rb +5 -7
- data/lib/listen/adapter/polling.rb +2 -1
- data/lib/listen/backend.rb +41 -0
- data/lib/listen/change.rb +45 -26
- data/lib/listen/cli.rb +3 -11
- data/lib/listen/directory.rb +31 -29
- data/lib/listen/event/config.rb +59 -0
- data/lib/listen/event/loop.rb +113 -0
- data/lib/listen/event/processor.rb +122 -0
- data/lib/listen/event/queue.rb +54 -0
- data/lib/listen/file.rb +9 -9
- data/lib/listen/fsm.rb +131 -0
- data/lib/listen/internals/thread_pool.rb +1 -1
- data/lib/listen/listener.rb +66 -305
- data/lib/listen/listener/config.rb +45 -0
- data/lib/listen/logger.rb +32 -0
- data/lib/listen/options.rb +1 -1
- data/lib/listen/queue_optimizer.rb +38 -20
- data/lib/listen/record.rb +50 -65
- data/lib/listen/silencer/controller.rb +48 -0
- data/lib/listen/version.rb +1 -1
- metadata +12 -21
- data/lib/listen/adapter/tcp.rb +0 -88
- data/lib/listen/internals/logging.rb +0 -35
- data/lib/listen/tcp.rb +0 -8
- data/lib/listen/tcp/broadcaster.rb +0 -79
- data/lib/listen/tcp/message.rb +0 -50
data/lib/listen/adapter/tcp.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'celluloid/io'
|
2
|
-
|
3
|
-
require 'listen/tcp/message'
|
4
|
-
|
5
|
-
module Listen
|
6
|
-
module Adapter
|
7
|
-
# Adapter to receive file system modifications over TCP
|
8
|
-
class TCP < Base
|
9
|
-
OS_REGEXP = // # match any
|
10
|
-
|
11
|
-
include Celluloid::IO
|
12
|
-
finalizer :finalize
|
13
|
-
|
14
|
-
DEFAULTS = {
|
15
|
-
host: 'localhost',
|
16
|
-
port: '4000'
|
17
|
-
}
|
18
|
-
|
19
|
-
attr_reader :buffer, :socket
|
20
|
-
|
21
|
-
# Initializes and starts a Celluloid::IO-powered TCP-recipient
|
22
|
-
def start
|
23
|
-
attempts ||= 3
|
24
|
-
_log :info, "TCP: opening socket #{options.host}:#{options.port}"
|
25
|
-
@socket = TCPSocket.new(options.host, options.port)
|
26
|
-
@buffer = ''
|
27
|
-
async.run
|
28
|
-
rescue Celluloid::Task::TerminatedError
|
29
|
-
_log :debug, "TCP adapter was terminated: #{$ERROR_INFO.inspect}"
|
30
|
-
rescue Errno::ECONNREFUSED
|
31
|
-
sleep 1
|
32
|
-
attempts -= 1
|
33
|
-
_log :warn, "TCP.start: #{$ERROR_INFO.inspect}"
|
34
|
-
retry if attempts > 0
|
35
|
-
_log :error, format('TCP.start: %s:%s', $ERROR_INFO.inspect,
|
36
|
-
$ERROR_POSITION * "\n")
|
37
|
-
raise
|
38
|
-
rescue
|
39
|
-
_log :error, format('TCP.start: %s:%s', $ERROR_INFO.inspect,
|
40
|
-
$ERROR_POSITION * "\n")
|
41
|
-
raise
|
42
|
-
end
|
43
|
-
|
44
|
-
# Cleans up buffer and socket
|
45
|
-
def finalize
|
46
|
-
@buffer = nil
|
47
|
-
return unless @socket
|
48
|
-
|
49
|
-
@socket.close
|
50
|
-
@socket = nil
|
51
|
-
end
|
52
|
-
|
53
|
-
# Number of bytes to receive at a time
|
54
|
-
RECEIVE_WINDOW = 1024
|
55
|
-
|
56
|
-
# Continuously receive and asynchronously handle data
|
57
|
-
def run
|
58
|
-
while (data = @socket.recv(RECEIVE_WINDOW))
|
59
|
-
async.handle_data(data)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Buffers incoming data and handles messages accordingly
|
64
|
-
def handle_data(data)
|
65
|
-
@buffer << data
|
66
|
-
while (message = Listen::TCP::Message.from_buffer(@buffer))
|
67
|
-
handle_message(message)
|
68
|
-
end
|
69
|
-
rescue
|
70
|
-
_log :error, format('TCP.handle_data crashed: %s:%s', $ERROR_INFO,
|
71
|
-
$ERROR_POSITION * "\n")
|
72
|
-
raise
|
73
|
-
end
|
74
|
-
|
75
|
-
# Handles incoming message by notifying of path changes
|
76
|
-
def handle_message(message)
|
77
|
-
type, change, dir, path, _ = message.object
|
78
|
-
_log(:debug) { "TCP message: #{[type, change, dir, path].inspect}" }
|
79
|
-
|
80
|
-
_queue_change(type.to_sym, Pathname(dir), path, change: change.to_sym)
|
81
|
-
end
|
82
|
-
|
83
|
-
def self.local_fs?
|
84
|
-
false
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'celluloid/logger'
|
2
|
-
|
3
|
-
module Listen
|
4
|
-
module Internals
|
5
|
-
module Logging
|
6
|
-
def _info(*args, &block)
|
7
|
-
_log(:info, *args, &block)
|
8
|
-
end
|
9
|
-
|
10
|
-
def _warn(*args, &block)
|
11
|
-
_log(:warn, *args, &block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def _debug(*args, &block)
|
15
|
-
_log(:debug, *args, &block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def _log(*args, &block)
|
19
|
-
if block
|
20
|
-
Celluloid::Logger.send(*args, block.call)
|
21
|
-
else
|
22
|
-
Celluloid::Logger.send(*args)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def _format_error(fmt)
|
27
|
-
format(fmt, $ERROR_INFO, ", Backtrace: \n" + $ERROR_POSITION * "\n")
|
28
|
-
end
|
29
|
-
|
30
|
-
def _error_exception(fmt)
|
31
|
-
_log :error, _format_error(fmt)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/lib/listen/tcp.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'celluloid/io'
|
2
|
-
|
3
|
-
module Listen
|
4
|
-
module TCP
|
5
|
-
class Broadcaster
|
6
|
-
include Celluloid::IO
|
7
|
-
|
8
|
-
finalizer :finalize
|
9
|
-
|
10
|
-
# Initializes a Celluloid::IO-powered TCP-broadcaster
|
11
|
-
#
|
12
|
-
# @param [String] host to broadcast on
|
13
|
-
# @param [String] port to broadcast on
|
14
|
-
#
|
15
|
-
# Note: Listens on all addresses when host is nil
|
16
|
-
#
|
17
|
-
def initialize(host, port)
|
18
|
-
@sockets = []
|
19
|
-
_log :debug, format('Broadcaster: tcp server listening on: %s:%s',
|
20
|
-
host, port)
|
21
|
-
@server = TCPServer.new(host, port)
|
22
|
-
rescue
|
23
|
-
_log :error, format('Broadcaster.initialize: %s:%s', $ERROR_INFO,
|
24
|
-
$ERROR_POSITION * "\n")
|
25
|
-
raise
|
26
|
-
end
|
27
|
-
|
28
|
-
# Asynchronously start accepting connections
|
29
|
-
def start
|
30
|
-
async.run
|
31
|
-
end
|
32
|
-
|
33
|
-
# Cleans up sockets and server
|
34
|
-
def finalize
|
35
|
-
@sockets.map(&:close) if @sockets
|
36
|
-
@sockets = nil
|
37
|
-
|
38
|
-
return unless @server
|
39
|
-
@server.close
|
40
|
-
@server = nil
|
41
|
-
end
|
42
|
-
|
43
|
-
# Broadcasts given payload to all connected sockets
|
44
|
-
def broadcast(payload)
|
45
|
-
active_sockets = @sockets.select do |socket|
|
46
|
-
_unicast(socket, payload)
|
47
|
-
end
|
48
|
-
@sockets.replace(active_sockets)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Continuously accept and handle incoming connections
|
52
|
-
def run
|
53
|
-
while (socket = @server.accept)
|
54
|
-
@sockets << socket
|
55
|
-
end
|
56
|
-
rescue Celluloid::Task::TerminatedError
|
57
|
-
_log :debug, "TCP adapter was terminated: #{$ERROR_INFO}"
|
58
|
-
rescue
|
59
|
-
_log :error, format('Broadcaster.run: %s:%s', $ERROR_INFO,
|
60
|
-
$ERROR_POSITION * "\n")
|
61
|
-
raise
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def _log(type, message)
|
67
|
-
Celluloid::Logger.send(type, message)
|
68
|
-
end
|
69
|
-
|
70
|
-
def _unicast(socket, payload)
|
71
|
-
socket.write(payload)
|
72
|
-
true
|
73
|
-
rescue IOError, Errno::ECONNRESET, Errno::EPIPE
|
74
|
-
_log :debug, "Broadcaster failed: #{socket.inspect}"
|
75
|
-
false
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
data/lib/listen/tcp/message.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module Listen
|
4
|
-
module TCP
|
5
|
-
class Message
|
6
|
-
attr_reader :body, :object, :payload, :size
|
7
|
-
|
8
|
-
HEADER_SIZE = 4
|
9
|
-
HEADER_FORMAT = 'N'
|
10
|
-
PAYLOAD_FORMAT = "#{HEADER_FORMAT}a*"
|
11
|
-
|
12
|
-
# Initializes a new message
|
13
|
-
#
|
14
|
-
# @param [Object] object to initialize message with
|
15
|
-
#
|
16
|
-
def initialize(*args)
|
17
|
-
self.object = args
|
18
|
-
end
|
19
|
-
|
20
|
-
# Generates message size and payload for given object
|
21
|
-
def object=(obj)
|
22
|
-
@object = obj
|
23
|
-
@body = JSON.generate(@object)
|
24
|
-
@size = @body.bytesize
|
25
|
-
@payload = [@size, @body].pack(PAYLOAD_FORMAT)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Extracts message size and loads object from given payload
|
29
|
-
def payload=(payload)
|
30
|
-
@payload = payload
|
31
|
-
@size, @body = @payload.unpack(PAYLOAD_FORMAT)
|
32
|
-
@object = JSON.parse(@body)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Extracts a message from given buffer
|
36
|
-
def self.from_buffer(buffer)
|
37
|
-
if buffer.bytesize > HEADER_SIZE
|
38
|
-
size = buffer.unpack(HEADER_FORMAT).first
|
39
|
-
payload_size = HEADER_SIZE + size
|
40
|
-
if buffer.bytesize >= payload_size
|
41
|
-
payload = buffer.slice!(0...payload_size)
|
42
|
-
new.tap do |message|
|
43
|
-
message.payload = payload
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|