117 lines
2.5 KiB
Ruby
117 lines
2.5 KiB
Ruby
# 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
|