diff --git a/.rubocop.yml b/.rubocop.yml index e8814315..87947673 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -13,6 +13,8 @@ AllCops: Style/Documentation: Enabled: false +Style/NumericLiterals: + Enabled: false # Length is not useful indicator Metrics/LineLength: @@ -47,5 +49,5 @@ Next: Enabled: false # Enforce LF line endings, even when on Windows -Style/EndOfLine: +Layout/EndOfLine: EnforcedStyle: lf diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 32e93b31..78b4c653 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2017-05-24 15:29:50 -0700 using RuboCop version 0.48.1. +# on 2017-06-16 13:39:02 -0700 using RuboCop version 0.49.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -12,191 +12,6 @@ Lint/HandleExceptions: - 'lib/puppet-languageserver/simple_tcp_server.rb' # Offense count: 1 -Lint/Loop: +Lint/ScriptPermission: Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -Lint/RescueException: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. -Lint/UnusedBlockArgument: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 3 -Lint/UselessAssignment: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Configuration parameters: CountBlocks. -Metrics/BlockNesting: - Max: 4 - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: AllowAdjacentOneLineDefs, NumberOfEmptyLines. -Style/EmptyLineBetweenDefs: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/EmptyLinesAroundExceptionHandlingKeywords: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Configuration parameters: MinBodyLength. -Style/GuardClause: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 8 -# Cop supports --auto-correct. -# Configuration parameters: SupportedStyles, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. -# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys -Style/HashSyntax: - EnforcedStyle: hash_rockets - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: normal, rails -Style/IndentationConsistency: - Exclude: - - 'lib/puppet-languageserver/json_rpc_handler.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: Width, IgnoredPatterns. -Style/IndentationWidth: - Exclude: - - 'lib/puppet-languageserver/json_rpc_handler.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -Style/MutableConstant: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 8 -# Cop supports --auto-correct. -# Configuration parameters: Strict. -Style/NumericLiterals: - MinDigits: 8 - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. -# SupportedStyles: predicate, comparison -Style/NumericPredicate: - Exclude: - - 'spec/**/*' - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/Proc: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/RedundantBegin: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/RedundantParentheses: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 6 -# Cop supports --auto-correct. -Style/RescueModifier: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/SelfAssignment: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: AllowAsExpressionSeparator. -Style/Semicolon: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/SpaceBeforeSemicolon: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 24 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Style/SpaceInsideBlockBraces: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/SpaceInsideBrackets: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces. -# SupportedStyles: space, no_space, compact -# SupportedStylesForEmptyBraces: space, no_space -Style/SpaceInsideHashLiteralBraces: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 5 -# Cop supports --auto-correct. -Style/SpaceInsideParens: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 5 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline. -# SupportedStyles: single_quotes, double_quotes -Style/StringLiterals: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: IgnoredMethods. -# IgnoredMethods: respond_to, define_method -Style/SymbolProc: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 15 -# Cop supports --auto-correct. -Style/TrailingWhitespace: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/ZeroLengthPredicate: - Exclude: - - 'lib/puppet-languageserver/simple_tcp_server.rb' + - 'puppet-languageserver' diff --git a/lib/puppet-languageserver.rb b/lib/puppet-languageserver.rb index 7838d9e9..0925013c 100644 --- a/lib/puppet-languageserver.rb +++ b/lib/puppet-languageserver.rb @@ -13,21 +13,18 @@ require 'optparse' require 'logger' -# Global variable holding the logger class -$logger = nil - module PuppetLanguageServer class CommandLineParser def self.parse(options) # Set defaults here args = { - :port => 8081, - :ipaddress => '127.0.0.1', - :stop_on_client_exit => true, - :connection_timeout => 10, - :preload_puppet => true, - :debug => nil, - :fast_start_tcpserver => true + port: 8081, + ipaddress: '127.0.0.1', + stop_on_client_exit: true, + connection_timeout: 10, + preload_puppet: true, + debug: nil, + fast_start_tcpserver: true } opt_parser = OptionParser.new do |opts| @@ -78,32 +75,32 @@ def self.parse(options) end def self.log_message(severity, message) - return if $logger.nil? - + return if @logger.nil? + case severity when :debug - $logger.debug(message) + @logger.debug(message) when :info - $logger.info(message) + @logger.info(message) when :warn - $logger.info(message) + @logger.info(message) when :error - $logger.error(message) + @logger.error(message) when :fatal - $logger.fatal(message) + @logger.fatal(message) else - $logger.unknown(message) + @logger.unknown(message) end end def self.init_puppet(options) if options[:debug].nil? - $logger = nil - elsif options[:debug].downcase == 'stdout' - $logger = Logger.new($stdout) + @logger = nil + elsif options[:debug].casecmp 'stdout' + @logger = Logger.new($stdout) elsif !options[:debug].to_s.empty? # Log to file - $logger = Logger.new(options[:debug]) + @logger = Logger.new(options[:debug]) end log_message(:info, "Language Server is v#{PuppetLanguageServer.version}") log_message(:info, "Using Puppet v#{Puppet.version}") diff --git a/lib/puppet-languageserver/document_validator.rb b/lib/puppet-languageserver/document_validator.rb index 8918b8fd..35c8e4ee 100644 --- a/lib/puppet-languageserver/document_validator.rb +++ b/lib/puppet-languageserver/document_validator.rb @@ -45,7 +45,7 @@ def self.validate(content, _max_problems = 100) Puppet[:code] = content env = Puppet.lookup(:current_environment) loaders = Puppet::Pops::Loaders.new(env) - Puppet.override({ :loaders => loaders }, 'For puppet parser validate') do + Puppet.override({ loaders: loaders }, 'For puppet parser validate') do begin validation_environment = env validation_environment.check_for_reparse diff --git a/lib/puppet-languageserver/hover_provider.rb b/lib/puppet-languageserver/hover_provider.rb index e9fef5db..e599b06c 100644 --- a/lib/puppet-languageserver/hover_provider.rb +++ b/lib/puppet-languageserver/hover_provider.rb @@ -78,7 +78,6 @@ def self.get_hover_content_for_access_expression(item, expr) content end - # Content generation functions def self.get_fact_content(factname) return nil unless PuppetLanguageServer::FacterHelper.facts.key?(factname) diff --git a/lib/puppet-languageserver/json_rpc_handler.rb b/lib/puppet-languageserver/json_rpc_handler.rb index c3f5c9fa..aa1a7f77 100644 --- a/lib/puppet-languageserver/json_rpc_handler.rb +++ b/lib/puppet-languageserver/json_rpc_handler.rb @@ -110,15 +110,15 @@ def receive_data(data) end def send_response(response) + PuppetLanguageServer.log_message(:debug, "--- OUTBOUND\n#{response}\n---") + size = response.bytesize if response.respond_to?(:bytesize) -# DEBUG ONLY -PuppetLanguageServer.log_message(:debug, "--- OUTBOUND\n#{response}\n---") send_data "Content-Length: #{size}\r\n\r\n" + response end def parse_data(data) -# DEBUG ONLY -PuppetLanguageServer.log_message(:debug, "--- INBOUND\n#{data}\n---") + PuppetLanguageServer.log_message(:debug, "--- INBOUND\n#{data}\n---") + result = JSON.parse(data) received_parsed_object(result) end diff --git a/lib/puppet-languageserver/message_router.rb b/lib/puppet-languageserver/message_router.rb index 471dc29f..3671f74a 100644 --- a/lib/puppet-languageserver/message_router.rb +++ b/lib/puppet-languageserver/message_router.rb @@ -54,7 +54,7 @@ def receive_request(request) request.reply_result(LanguageServer::PuppetCompilation.create('data' => '')) if resources.nil? || resources.length.zero? # TODO: Should probably move this to a helper? - content = resources.map { |res| res.to_manifest }.join("\n\n") + "\n" + content = resources.map(&:to_manifest).join("\n\n") + "\n" request.reply_result(LanguageServer::PuppetCompilation.create('data' => content)) when 'puppet/compileNodeGraph' diff --git a/lib/puppet-languageserver/puppet_helper.rb b/lib/puppet-languageserver/puppet_helper.rb index dae3ec8b..ce98bb8a 100644 --- a/lib/puppet-languageserver/puppet_helper.rb +++ b/lib/puppet-languageserver/puppet_helper.rb @@ -108,9 +108,7 @@ def self._reset def self.prune_resource_parameters(resources) # From https://github.com/puppetlabs/puppet/blob/488661d84e54904124514ab9e4500e81b10f84d1/lib/puppet/application/resource.rb#L146-L148 if resources.is_a?(Array) - resources.map do |resource| - resource.prune_parameters - end + resources.map(&:prune_parameters) else resources.prune_parameters end @@ -121,7 +119,7 @@ def self._load_types @types_hash = {} # This is an expensive call # From https://github.com/puppetlabs/puppet/blob/ebd96213cab43bb2a8071b7ac0206c3ed0be8e58/lib/puppet/metatype/manager.rb#L182-L189 - typeloader = Puppet::Util::Autoload.new(self, "puppet/type") + typeloader = Puppet::Util::Autoload.new(self, 'puppet/type') typeloader.loadall Puppet::Type.eachtype do |type| diff --git a/lib/puppet-languageserver/puppet_parser_helper.rb b/lib/puppet-languageserver/puppet_parser_helper.rb index bd238f1f..955e2209 100644 --- a/lib/puppet-languageserver/puppet_parser_helper.rb +++ b/lib/puppet-languageserver/puppet_parser_helper.rb @@ -77,7 +77,7 @@ def self.object_under_cursor(content, line_num, char_num, multiple_attempts = fa when :remove_word next_char = get_char_at(content, line_offsets, line_num, char_num) - while /[[:word:]]/.match(next_char) + while /[[:word:]]/ =~ next_char move_offset -= 1 next_char = get_char_at(content, line_offsets, line_num, char_num + move_offset) diff --git a/lib/puppet-languageserver/simple_tcp_server.rb b/lib/puppet-languageserver/simple_tcp_server.rb index 2938c44b..768387c3 100644 --- a/lib/puppet-languageserver/simple_tcp_server.rb +++ b/lib/puppet-languageserver/simple_tcp_server.rb @@ -48,13 +48,23 @@ def close_connection end class SimpleTCPServer - IO_LOCKER = Mutex.new - EVENTS = [] - E_LOCKER = Mutex.new - SERVICES = {} - S_LOCKER = Mutex.new - IO_CONNECTION_DIC = {} - C_LOCKER = Mutex.new + class << self + attr_reader :io_locker + attr_reader :events + attr_reader :e_locker + attr_reader :services + attr_reader :s_locker + attr_reader :io_connection_dic + attr_reader :c_locker + end + + @io_locker = Mutex.new + @events = [] + @e_locker = Mutex.new + @services = {} + @s_locker = Mutex.new + @io_connection_dic = {} + @c_locker = Mutex.new def log(message) # Override this to recieve log messages @@ -65,20 +75,17 @@ def log(message) # this code will be called when a socket recieves data. # @api private def get_data(io, connection_data) - begin - data = io.recv_nonblock( 1048576 ) # with maximum number of bytes to read at a time... - raise "Received a 0byte payload" if data.length == 0 + data = io.recv_nonblock(1048576) # with maximum number of bytes to read at a time... + raise 'Received a 0byte payload' if data.length.zero? - # We're already in a callback so no need to invoke as a callback - connection_data[:handler].receive_data(data) - - rescue => e - # should also log error - remove_connection(io) - log("Closed socket due to error - #{e}\n#{e.backtrace}") - end + # We're already in a callback so no need to invoke as a callback + connection_data[:handler].receive_data(data) + rescue => e + # should also log error + remove_connection(io) + log("Closed socket due to error - #{e}\n#{e.backtrace}") end - + ######### # main loop and activation code # @@ -92,16 +99,20 @@ def start(handler = PuppetLanguageServer::SimpleTCPServerConnection, connection_ # prepare threads exit_flag = false threads = [] - thread_cycle = Proc.new do - io_review rescue false + thread_cycle = proc do + begin + io_review + rescue + false + end true while fire_event end - (max_threads).times { Thread.new { thread_cycle.call until exit_flag } } - + max_threads.times { Thread.new { thread_cycle.call until exit_flag } } + @handler_klass = handler @handler_start_options = connection_options @server_options = connection_options # Currently the same as handler options. Could be different later. - log("Services running. Press ^C to stop") + log('Services running. Press ^C to stop') # sleep until trap raises exception (cycling might cause the main thread to loose signals that might be caught inside rescue clauses) kill_timer = connection_options[:connection_timeout] @@ -110,30 +121,34 @@ def start(handler = PuppetLanguageServer::SimpleTCPServerConnection, connection_ log('Will stop the server when client disconnects') if !@server_options[:stop_on_client_exit].nil? && @server_options[:stop_on_client_exit] # Output to STDOUT. This is required by Langugage Client so it knows the server is now running - S_LOCKER.synchronize do - SERVICES.each do |service,options| + self.class.s_locker.synchronize do + self.class.services.each do |_service, options| $stdout.write("LANGUAGE SERVER RUNNING #{options[:hostname]}:#{options[:port]}\n") end end $stdout.flush - (begin - sleep(1) - # The kill_timer is used to stop the server if no clients have connected in X seconds - # a value of 0 or less will not timeout. - if kill_timer > 0 - kill_timer = kill_timer - 1 - if kill_timer == 0 - connection_count = 0 - C_LOCKER.synchronize { connection_count = IO_CONNECTION_DIC.count } - if connection_count.zero? - log("No connection has been received in #{connection_options[:connection_timeout]} seconds. Shutting down server.") - stop_services + loop do + begin + sleep(1) + # The kill_timer is used to stop the server if no clients have connected in X seconds + # a value of 0 or less will not timeout. + if kill_timer > 0 + kill_timer -= 1 + if kill_timer.zero? + connection_count = 0 + self.class.c_locker.synchronize { connection_count = self.class.io_connection_dic.count } + if connection_count.zero? + log("No connection has been received in #{connection_options[:connection_timeout]} seconds. Shutting down server.") + stop_services + end end end + rescue true end - end until SERVICES.empty?) rescue true - + break if self.class.services.empty? + end + # start shutdown. exit_flag = true log('Started shutdown process. Press ^C to force quit.') @@ -142,64 +157,65 @@ def start(handler = PuppetLanguageServer::SimpleTCPServerConnection, connection_ # disconnect active connections stop_connections # cycle down threads - log("Waiting for workers to cycle down") - threads.each {|t| t.join if t.alive?} - + log('Waiting for workers to cycle down') + threads.each { |t| t.join if t.alive? } + # rundown any active events thread_cycle.call end - - + ####################### ## Events (Callbacks) / Multi-tasking Platform # returns true if there are any unhandled events # @api private def events? - E_LOCKER.synchronize {!EVENTS.empty?} + self.class.e_locker.synchronize { !self.class.events.empty? } end - + # pushes an event to the event's stack # if a block is passed along, it will be used as a callback: the block will be called with the values returned by the handler's `call` method. # @api private def push_event(handler, *args, &block) if block - E_LOCKER.synchronize {EVENTS << [(Proc.new {|a| push_event block, handler.call(*a)} ), args]} + self.class.e_locker.synchronize { self.class.events << [(proc { |a| push_event block, handler.call(*a) }), args] } else - E_LOCKER.synchronize {EVENTS << [handler, args]} + self.class.e_locker.synchronize { self.class.events << [handler, args] } end end - + # Runs the block asynchronously by pushing it as an event to the event's stack # # @api private def run_async(*args, &block) - E_LOCKER.synchronize {EVENTS << [ block, args ]} if block + self.class.e_locker.synchronize { self.class.events << [block, args] } if block !block.nil? end - + # creates an asynchronous call to a method, with an optional callback (shortcut) # @api private def callback(object, method, *args, &block) push_event object.method(method), *args, &block end - + # event handling FIFO # @api private def fire_event - event = E_LOCKER.synchronize {EVENTS.shift} + event = self.class.e_locker.synchronize { self.class.events.shift } return false unless event begin event[0].call(*event[1]) - rescue OpenSSL::SSL::SSLError => e - log("SSL Bump - SSL Certificate refused?") + rescue OpenSSL::SSL::SSLError => _ + log('SSL Bump - SSL Certificate refused?') + # rubocop:disable RescueException rescue Exception => e raise if e.is_a?(SignalException) || e.is_a?(SystemExit) error e end + # rubocop:enable RescueException + true end - - + ##### # Reactor # @@ -207,36 +223,41 @@ def fire_event # it will accept new connections and react to socket input # @api private def io_review - IO_LOCKER.synchronize do - return false unless EVENTS.empty? - united = SERVICES.keys + IO_CONNECTION_DIC.keys + self.class.io_locker.synchronize do + return false unless self.class.events.empty? + united = self.class.services.keys + self.class.io_connection_dic.keys return false if united.empty? - io_r = (IO.select(united, nil, united, 0.1) ) + io_r = IO.select(united, nil, united, 0.1) if io_r io_r[0].each do |io| - if SERVICES[io] + if self.class.services[io] begin - callback(self, :add_connection, io.accept_nonblock, SERVICES[io]) - rescue Errno::EWOULDBLOCK => e - + callback(self, :add_connection, io.accept_nonblock, self.class.services[io]) + rescue Errno::EWOULDBLOCK => _ rescue => e - # log + log(e.message) end - elsif IO_CONNECTION_DIC[io] - callback(self, :get_data, io, IO_CONNECTION_DIC[io] ) + elsif self.class.io_connection_dic[io] + callback(self, :get_data, io, self.class.io_connection_dic[io]) else - log("what?!") + log('what?!') remove_connection(io) - SERVICES.delete(io) + self.class.services.delete(io) + end + end + io_r[2].each do |io| + begin + (remove_connection(io) || self.class.services.delete(io)).close + rescue + true end end - io_r[2].each { |io| (remove_connection(io) || SERVICES.delete(io)).close rescue true } end end callback self, :clear_connections true end - + ####################### # IO - listening sockets (services) @@ -246,7 +267,7 @@ def add_service(hostname = '127.0.0.1', port = 8081, parameters = {}) parameters[:hostname] = hostname parameters.update port if port.is_a?(Hash) service = TCPServer.new(parameters[:hostname], parameters[:port]) - S_LOCKER.synchronize {SERVICES[service] = parameters} + self.class.s_locker.synchronize { self.class.services[service] = parameters } callback(self, :log, "Started listening on #{hostname}:#{port}.") true end @@ -254,7 +275,17 @@ def add_service(hostname = '127.0.0.1', port = 8081, parameters = {}) # @api public def stop_services log('Stopping services') - S_LOCKER.synchronize {SERVICES.each {|s, p| (s.close rescue true); log("Stopped listening on #{p[:hostname]}:#{p[:port]}") }; SERVICES.clear } + self.class.s_locker.synchronize do + self.class.services.each do |s, p| + begin + s.close + rescue + true + end + log("Stopped listening on #{p[:hostname]}:#{p[:port]}") + end + self.class.services.clear + end end # @api public @@ -267,33 +298,58 @@ def remove_connection_async(io) # @api private def stop_connections - C_LOCKER.synchronize {IO_CONNECTION_DIC.each {|io, params| io.close rescue true} ; IO_CONNECTION_DIC.clear} + self.class.c_locker.synchronize do + self.class.io_connection_dic.each do |io, _params| + begin + io.close + rescue + true + end + end + self.class.io_connection_dic.clear + end end + # @api private def add_connection(io, service_object) handler = @handler_klass.new(@handler_start_options) handler.socket = io handler.simple_tcp_server = self - C_LOCKER.synchronize {IO_CONNECTION_DIC[io] = { :handler => handler, :service => service_object} } if io + if io + self.class.c_locker.synchronize do + self.class.io_connection_dic[io] = { handler: handler, service: service_object } + end + end callback(handler, :post_init) end + # @api private def remove_connection(io) # This needs to be synchronous - (IO_CONNECTION_DIC[io])[:handler].unbind + self.class.io_connection_dic[io][:handler].unbind connection_count = 0 - C_LOCKER.synchronize { IO_CONNECTION_DIC.delete io; connection_count = IO_CONNECTION_DIC.count; io.close rescue true } - - if connection_count == 0 && !@server_options[:stop_on_client_exit].nil? && @server_options[:stop_on_client_exit] - callback(self, :log, 'Client has disconnected. Shutting down server.') - callback(self, :stop_services) + self.class.c_locker.synchronize do + self.class.io_connection_dic.delete io + connection_count = self.class.io_connection_dic.count + begin + io.close + rescue + true + end end + + return unless connection_count.zero? && !@server_options[:stop_on_client_exit].nil? && @server_options[:stop_on_client_exit] + callback(self, :log, 'Client has disconnected. Shutting down server.') + callback(self, :stop_services) end # clears closed connections from the stack # @api private def clear_connections - C_LOCKER.synchronize { IO_CONNECTION_DIC.delete_if {|c| c.closed? } } - end + # Using a SymbolProc here does not work + # rubocop:disable Style/SymbolProc + self.class.c_locker.synchronize { self.class.io_connection_dic.delete_if { |c| c.closed? } } + # rubocop:enable Style/SymbolProc + end end end diff --git a/lib/puppet-languageserver/version.rb b/lib/puppet-languageserver/version.rb index c77f9118..94966bf5 100644 --- a/lib/puppet-languageserver/version.rb +++ b/lib/puppet-languageserver/version.rb @@ -1,18 +1,16 @@ module PuppetLanguageServer - if not defined? PUPPETLANGUAGESERVERVERSION then - PUPPETLANGUAGESERVERVERSION = '0.0.1' - end + PUPPETLANGUAGESERVERVERSION = '0.0.1'.freeze unless defined? PUPPETLANGUAGESERVERVERSION # @api public # # @return [String] containing the langauge server version, e.g. "0.4.0" def self.version - version_file = File.join(File.dirname(__FILE__), 'VERSION') return @lang_server_version if @lang_server_version - if version = read_version_file(version_file) - @lang_server_version = version - end - @lang_server_version ||= PUPPETLANGUAGESERVERVERSION + + version_file = File.join(File.dirname(__FILE__), 'VERSION') + version = read_version_file(version_file) + + @lang_server_version = version ? version : PUPPETLANGUAGESERVERVERSION end # Sets the langauge server version @@ -30,9 +28,7 @@ def self.version=(version) # @return [String] the version -- for example: "0.4.0" or nil if the VERSION # file does not exist. def self.read_version_file(path) - if File.exists?(path) - File.read(path).chomp - end + File.read(path).chomp if File.exist?(path) end private_class_method :read_version_file end