This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Sass
|
||||
class Compiler
|
||||
# The {Dispatcher} class.
|
||||
#
|
||||
# It dispatches messages between multiple instances of {Host} and a single {Connection} to the compiler.
|
||||
class Dispatcher
|
||||
def initialize
|
||||
@id = 1
|
||||
@observers = {}.compare_by_identity
|
||||
@mutex = Mutex.new
|
||||
@connection = Connection.new
|
||||
@connection.listen(self)
|
||||
ForkTracker.add(self)
|
||||
end
|
||||
|
||||
def subscribe(observer)
|
||||
@mutex.synchronize do
|
||||
raise Errno::EBUSY if _closed?
|
||||
|
||||
id = @id
|
||||
@id = id.next
|
||||
@observers[id] = observer
|
||||
id
|
||||
end
|
||||
end
|
||||
|
||||
def unsubscribe(id)
|
||||
@mutex.synchronize do
|
||||
@observers.delete(id)
|
||||
|
||||
return unless @observers.empty?
|
||||
|
||||
if _closed?
|
||||
Thread.new do
|
||||
close
|
||||
end
|
||||
else
|
||||
_idle
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def close
|
||||
@mutex.synchronize do
|
||||
_close
|
||||
end
|
||||
@connection.close
|
||||
ForkTracker.delete(self)
|
||||
end
|
||||
|
||||
def closed?
|
||||
@connection.closed?
|
||||
end
|
||||
|
||||
def error(error)
|
||||
observers = @mutex.synchronize do
|
||||
_close
|
||||
@observers.values
|
||||
end
|
||||
|
||||
if observers.empty?
|
||||
close
|
||||
else
|
||||
observers.each do |observer|
|
||||
observer.error(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def receive_proto(id, proto)
|
||||
case id
|
||||
when 1...0xffffffff
|
||||
@mutex.synchronize { @observers[id] }&.receive_proto(proto)
|
||||
when 0
|
||||
outbound_message = EmbeddedProtocol::OutboundMessage.decode(proto)
|
||||
oneof = outbound_message.message
|
||||
message = outbound_message.public_send(oneof)
|
||||
@mutex.synchronize { @observers[message.id] }&.public_send(oneof, message)
|
||||
when 0xffffffff
|
||||
outbound_message = EmbeddedProtocol::OutboundMessage.decode(proto)
|
||||
oneof = outbound_message.message
|
||||
message = outbound_message.public_send(oneof)
|
||||
raise Errno::EPROTO, message.message
|
||||
else
|
||||
raise Errno::EPROTO
|
||||
end
|
||||
end
|
||||
|
||||
def send_proto(...)
|
||||
@connection.write(...)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _close
|
||||
@id = 0xffffffff
|
||||
end
|
||||
|
||||
def _closed?
|
||||
@id == 0xffffffff
|
||||
end
|
||||
|
||||
def _idle
|
||||
@id = 1
|
||||
end
|
||||
|
||||
def _idle?
|
||||
@id == 1
|
||||
end
|
||||
end
|
||||
|
||||
private_constant :Dispatcher
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user