puppet-editor-services 2.0.4

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.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +510 -0
  3. data/CODEOWNERS +2 -0
  4. data/CODE_OF_CONDUCT.md +46 -0
  5. data/CONTRIBUTING.md +54 -0
  6. data/Gemfile +53 -0
  7. data/LICENSE +201 -0
  8. data/README.md +308 -0
  9. data/Rakefile +185 -0
  10. data/bin/puppet-debugserver +8 -0
  11. data/bin/puppet-languageserver +7 -0
  12. data/bin/puppet-languageserver-sidecar +7 -0
  13. data/lib/dsp/dsp.rb +7 -0
  14. data/lib/dsp/dsp_base.rb +62 -0
  15. data/lib/dsp/dsp_protocol.rb +4619 -0
  16. data/lib/lsp/lsp.rb +10 -0
  17. data/lib/lsp/lsp_base.rb +63 -0
  18. data/lib/lsp/lsp_custom.rb +170 -0
  19. data/lib/lsp/lsp_enums.rb +143 -0
  20. data/lib/lsp/lsp_protocol.rb +2785 -0
  21. data/lib/lsp/lsp_protocol_callhierarchy.proposed.rb +239 -0
  22. data/lib/lsp/lsp_protocol_colorprovider.rb +100 -0
  23. data/lib/lsp/lsp_protocol_configuration.rb +82 -0
  24. data/lib/lsp/lsp_protocol_declaration.rb +73 -0
  25. data/lib/lsp/lsp_protocol_foldingrange.rb +129 -0
  26. data/lib/lsp/lsp_protocol_implementation.rb +75 -0
  27. data/lib/lsp/lsp_protocol_progress.rb +200 -0
  28. data/lib/lsp/lsp_protocol_selectionrange.rb +79 -0
  29. data/lib/lsp/lsp_protocol_sematictokens.proposed.rb +340 -0
  30. data/lib/lsp/lsp_protocol_typedefinition.rb +75 -0
  31. data/lib/lsp/lsp_protocol_workspacefolders.rb +174 -0
  32. data/lib/lsp/lsp_types.rb +1534 -0
  33. data/lib/puppet-debugserver/debug_session/break_points.rb +137 -0
  34. data/lib/puppet-debugserver/debug_session/flow_control.rb +161 -0
  35. data/lib/puppet-debugserver/debug_session/hook_handlers.rb +295 -0
  36. data/lib/puppet-debugserver/debug_session/puppet_session_run_mode.rb +66 -0
  37. data/lib/puppet-debugserver/debug_session/puppet_session_state.rb +122 -0
  38. data/lib/puppet-debugserver/hooks.rb +132 -0
  39. data/lib/puppet-debugserver/message_handler.rb +277 -0
  40. data/lib/puppet-debugserver/puppet_debug_session.rb +541 -0
  41. data/lib/puppet-debugserver/puppet_monkey_patches.rb +118 -0
  42. data/lib/puppet-languageserver/client_session_state.rb +119 -0
  43. data/lib/puppet-languageserver/crash_dump.rb +50 -0
  44. data/lib/puppet-languageserver/epp/validation_provider.rb +34 -0
  45. data/lib/puppet-languageserver/facter_helper.rb +25 -0
  46. data/lib/puppet-languageserver/global_queues/sidecar_queue.rb +205 -0
  47. data/lib/puppet-languageserver/global_queues/single_instance_queue.rb +126 -0
  48. data/lib/puppet-languageserver/global_queues/validation_queue.rb +102 -0
  49. data/lib/puppet-languageserver/global_queues.rb +16 -0
  50. data/lib/puppet-languageserver/manifest/completion_provider.rb +331 -0
  51. data/lib/puppet-languageserver/manifest/definition_provider.rb +99 -0
  52. data/lib/puppet-languageserver/manifest/document_symbol_provider.rb +228 -0
  53. data/lib/puppet-languageserver/manifest/folding_provider.rb +226 -0
  54. data/lib/puppet-languageserver/manifest/format_on_type_provider.rb +143 -0
  55. data/lib/puppet-languageserver/manifest/hover_provider.rb +221 -0
  56. data/lib/puppet-languageserver/manifest/signature_provider.rb +169 -0
  57. data/lib/puppet-languageserver/manifest/validation_provider.rb +127 -0
  58. data/lib/puppet-languageserver/message_handler.rb +462 -0
  59. data/lib/puppet-languageserver/providers.rb +18 -0
  60. data/lib/puppet-languageserver/puppet_helper.rb +108 -0
  61. data/lib/puppet-languageserver/puppet_lexer_helper.rb +55 -0
  62. data/lib/puppet-languageserver/puppet_monkey_patches.rb +39 -0
  63. data/lib/puppet-languageserver/puppet_parser_helper.rb +212 -0
  64. data/lib/puppet-languageserver/puppetfile/validation_provider.rb +185 -0
  65. data/lib/puppet-languageserver/server_capabilities.rb +48 -0
  66. data/lib/puppet-languageserver/session_state/document_store.rb +272 -0
  67. data/lib/puppet-languageserver/session_state/language_client.rb +239 -0
  68. data/lib/puppet-languageserver/session_state/object_cache.rb +162 -0
  69. data/lib/puppet-languageserver/sidecar_protocol.rb +532 -0
  70. data/lib/puppet-languageserver/uri_helper.rb +46 -0
  71. data/lib/puppet-languageserver-sidecar/cache/base.rb +36 -0
  72. data/lib/puppet-languageserver-sidecar/cache/filesystem.rb +111 -0
  73. data/lib/puppet-languageserver-sidecar/cache/null.rb +27 -0
  74. data/lib/puppet-languageserver-sidecar/facter_helper.rb +41 -0
  75. data/lib/puppet-languageserver-sidecar/puppet_environment_monkey_patches.rb +52 -0
  76. data/lib/puppet-languageserver-sidecar/puppet_helper.rb +281 -0
  77. data/lib/puppet-languageserver-sidecar/puppet_modulepath_monkey_patches.rb +146 -0
  78. data/lib/puppet-languageserver-sidecar/puppet_monkey_patches.rb +9 -0
  79. data/lib/puppet-languageserver-sidecar/puppet_parser_helper.rb +77 -0
  80. data/lib/puppet-languageserver-sidecar/puppet_strings_helper.rb +399 -0
  81. data/lib/puppet-languageserver-sidecar/puppet_strings_monkey_patches.rb +16 -0
  82. data/lib/puppet-languageserver-sidecar/sidecar_protocol_extensions.rb +16 -0
  83. data/lib/puppet-languageserver-sidecar/workspace.rb +89 -0
  84. data/lib/puppet_debugserver.rb +164 -0
  85. data/lib/puppet_editor_services/connection/base.rb +62 -0
  86. data/lib/puppet_editor_services/connection/stdio.rb +25 -0
  87. data/lib/puppet_editor_services/connection/tcp.rb +34 -0
  88. data/lib/puppet_editor_services/handler/base.rb +16 -0
  89. data/lib/puppet_editor_services/handler/debug_adapter.rb +63 -0
  90. data/lib/puppet_editor_services/handler/json_rpc.rb +133 -0
  91. data/lib/puppet_editor_services/logging.rb +45 -0
  92. data/lib/puppet_editor_services/protocol/base.rb +27 -0
  93. data/lib/puppet_editor_services/protocol/debug_adapter.rb +135 -0
  94. data/lib/puppet_editor_services/protocol/debug_adapter_messages.rb +171 -0
  95. data/lib/puppet_editor_services/protocol/json_rpc.rb +241 -0
  96. data/lib/puppet_editor_services/protocol/json_rpc_messages.rb +200 -0
  97. data/lib/puppet_editor_services/server/base.rb +42 -0
  98. data/lib/puppet_editor_services/server/stdio.rb +85 -0
  99. data/lib/puppet_editor_services/server/tcp.rb +349 -0
  100. data/lib/puppet_editor_services/server.rb +15 -0
  101. data/lib/puppet_editor_services/version.rb +36 -0
  102. data/lib/puppet_editor_services.rb +8 -0
  103. data/lib/puppet_languageserver.rb +263 -0
  104. data/lib/puppet_languageserver_sidecar.rb +361 -0
  105. data/puppet-debugserver +11 -0
  106. data/puppet-editor-services.gemspec +29 -0
  107. data/puppet-languageserver +15 -0
  108. data/puppet-languageserver-sidecar +14 -0
  109. metadata +240 -0
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dsp/dsp'
4
+ require 'puppet_editor_services'
5
+
6
+ require 'optparse'
7
+ require 'logger'
8
+
9
+ module PuppetDebugServer
10
+ def self.version
11
+ PuppetEditorServices.version
12
+ end
13
+
14
+ def self.require_gems(options)
15
+ original_verbose = $VERBOSE
16
+ $VERBOSE = nil
17
+
18
+ # Use specific Puppet Gem version if possible
19
+ # Note that puppet is required implicitly in the monkey patches
20
+ # so we don't need to explicity require it here
21
+ unless options[:puppet_version].nil?
22
+ available_puppet_gems = Gem::Specification
23
+ .select { |item| item.name.casecmp('puppet').zero? }
24
+ .map { |item| item.version.to_s }
25
+ if available_puppet_gems.include?(options[:puppet_version])
26
+ gem 'puppet', options[:puppet_version]
27
+ else
28
+ log_message(:warn, "Unable to use puppet version #{options[:puppet_version]}, as only the following versions are available [#{available_puppet_gems.join(', ')}]")
29
+ end
30
+ end
31
+
32
+ %w[
33
+ message_handler
34
+ hooks
35
+ puppet_debug_session
36
+ debug_session/break_points
37
+ debug_session/hook_handlers
38
+ debug_session/flow_control
39
+ debug_session/puppet_session_run_mode
40
+ debug_session/puppet_session_state
41
+ puppet_monkey_patches
42
+ ].each do |lib|
43
+ require "puppet-debugserver/#{lib}"
44
+ rescue LoadError
45
+ require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-debugserver', lib))
46
+ end
47
+ ensure
48
+ $VERBOSE = original_verbose
49
+ end
50
+
51
+ class CommandLineParser
52
+ def self.parse(options)
53
+ # Set defaults here
54
+ args = {
55
+ port: nil,
56
+ ipaddress: 'localhost',
57
+ stop_on_client_exit: true,
58
+ connection_timeout: 10,
59
+ debug: nil,
60
+ puppet_version: nil
61
+ }
62
+
63
+ opt_parser = OptionParser.new do |opts|
64
+ opts.banner = 'Usage: puppet-debugserver.rb [options]'
65
+
66
+ opts.on('-pPORT', '--port=PORT', 'TCP Port to listen on. Default is random port') do |port|
67
+ args[:port] = port.to_i
68
+ end
69
+
70
+ opts.on('-ipADDRESS', '--ip=ADDRESS', "IP Address to listen on (0.0.0.0 for all interfaces). Default is #{args[:ipaddress]}") do |ipaddress|
71
+ args[:ipaddress] = ipaddress
72
+ end
73
+
74
+ opts.on('-tTIMEOUT', '--timeout=TIMEOUT', "Stop the Debug Server if a client does not connection within TIMEOUT seconds. A value of zero will not timeout. Default is #{args[:connection_timeout]} seconds") do |timeout|
75
+ args[:connection_timeout] = timeout.to_i
76
+ end
77
+
78
+ opts.on('--debug=DEBUG', "Output debug information. Either specify a filename or 'STDOUT'. Default is no debug output") do |debug|
79
+ args[:debug] = debug
80
+ end
81
+
82
+ opts.on('--puppet-version=TEXT', String, 'The version of the Puppet Gem to use (defaults to latest version if not specified or the version does not exist) e.g. --puppet-version=5.4.0') do |text|
83
+ args[:puppet_version] = text
84
+ end
85
+
86
+ opts.on('-h', '--help', 'Prints this help') do
87
+ puts opts
88
+ exit
89
+ end
90
+
91
+ opts.on('-v', '--version', 'Prints the Debug Server version') do
92
+ puts PuppetEditorServices.version
93
+ exit
94
+ end
95
+ end
96
+
97
+ opt_parser.parse!(options.dup)
98
+ args
99
+ end
100
+ end
101
+
102
+ def self.log_message(severity, message)
103
+ PuppetEditorServices.log_message(severity, message)
104
+ end
105
+
106
+ def self.init_puppet(options)
107
+ PuppetEditorServices.init_logging(options)
108
+ log_message(:info, "Debug Server is v#{PuppetDebugServer.version}")
109
+ log_message(:debug, 'Loading gems...')
110
+ require_gems(options)
111
+ require 'puppet'
112
+ log_message(:info, "Using Puppet v#{::Puppet.version}")
113
+
114
+ raise("Detected Puppet #{Puppet.version} however the Debug Server requires Puppet 5.0 and above") if Gem::Version.new(Puppet.version) < Gem::Version.new('5.0.0')
115
+
116
+ true
117
+ end
118
+
119
+ def self.rpc_server_async(options)
120
+ log_message(:info, 'Starting RPC Server (Async)...')
121
+
122
+ Thread.new do
123
+ Thread.current.abort_on_exception = true
124
+
125
+ require 'puppet_editor_services/protocol/debug_adapter'
126
+ require 'puppet_editor_services/server/tcp'
127
+
128
+ server_options = options.dup
129
+ protocol_options = { class: PuppetEditorServices::Protocol::DebugAdapter }.merge(options)
130
+ handler_options = { class: PuppetDebugServer::MessageHandler }.merge(options)
131
+ # TODO: Add max threads?
132
+ server_options[:servicename] = 'DEBUG SERVER'
133
+
134
+ log_message(:debug, 'Using TCP Server')
135
+ server = ::PuppetEditorServices::Server::Tcp.new(server_options, protocol_options, handler_options)
136
+ trap('INT') do
137
+ server.stop_services(true)
138
+ PuppetDebugServer::PuppetDebugSession.instance.flow_control.assert_flag(:terminate)
139
+ end
140
+ server.start
141
+
142
+ log_message(:info, 'Debug Server exited.')
143
+ # Forcibly kill the Debug Session
144
+ log_message(:info, 'Signalling Debug Session to terminate with extreme prejudice')
145
+ PuppetDebugServer::PuppetDebugSession.instance.force_terminate
146
+ end
147
+ end
148
+
149
+ def self.execute(rpc_thread)
150
+ debug_session = PuppetDebugServer::PuppetDebugSession.instance
151
+ debug_session.initialize_session
152
+
153
+ # TODO: Can I use a real mutex here? might be hard with the rpc_thread.alive? call
154
+ sleep(0.5) while !debug_session.flow_control.flag?(:start_puppet) && rpc_thread.alive? && !debug_session.flow_control.terminate?
155
+ return unless rpc_thread.alive? || debug_session.flow_control.terminate?
156
+
157
+ debug_session.run_puppet
158
+
159
+ return unless rpc_thread.alive?
160
+
161
+ debug_session.close
162
+ rpc_thread.join
163
+ end
164
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PuppetEditorServices
4
+ module Connection
5
+ class Base
6
+ attr_reader :server, :protocol
7
+
8
+ def initialize(server)
9
+ @server = server
10
+ @protocol = server.protocol_options[:class].new(self)
11
+ end
12
+
13
+ # Override this method
14
+ # @api public
15
+ def error?
16
+ false
17
+ end
18
+
19
+ # Override this method
20
+ # @api public
21
+ def send_data(_data)
22
+ false
23
+ end
24
+
25
+ # Shouldn't need to override this method
26
+ # @api public
27
+ def receive_data(data)
28
+ @protocol.receive_data(data)
29
+ rescue StandardError => e
30
+ server.log("Protocol #{@protocol.class} raised error #{e}: #{e.backtrace}")
31
+ end
32
+
33
+ # Override this method
34
+ # @api public
35
+ def close_after_writing
36
+ true
37
+ end
38
+
39
+ # Override this method
40
+ # @api public
41
+ def close
42
+ true
43
+ end
44
+
45
+ # Override this method if needed
46
+ # @api public
47
+ def post_init
48
+ server.log("Client #{id} has connected to the server")
49
+ end
50
+
51
+ # Override this method if needed
52
+ # @api public
53
+ def unbind
54
+ server.log("Client #{id} has disconnected from the server")
55
+ end
56
+
57
+ def id
58
+ object_id.to_s
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puppet_editor_services/connection/base'
4
+
5
+ module PuppetEditorServices
6
+ module Connection
7
+ class Stdio < ::PuppetEditorServices::Connection::Base
8
+ def send_data(data)
9
+ $editor_services_stdout.write(data) # rubocop:disable Style/GlobalVars We need this global var
10
+ true
11
+ end
12
+
13
+ def close_after_writing
14
+ $editor_services_stdout.flush # rubocop:disable Style/GlobalVars We need this global var
15
+ server.close_connection
16
+ true
17
+ end
18
+
19
+ def close
20
+ server.close_connection
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puppet_editor_services/connection/base'
4
+
5
+ module PuppetEditorServices
6
+ module Connection
7
+ class Tcp < ::PuppetEditorServices::Connection::Base
8
+ attr_accessor :socket
9
+
10
+ def initialize(server, socket)
11
+ super(server)
12
+ @socket = socket
13
+ end
14
+
15
+ def send_data(data)
16
+ return false if socket.nil?
17
+
18
+ socket.write(data)
19
+ true
20
+ end
21
+
22
+ def close_after_writing
23
+ socket.flush unless socket.nil?
24
+ server.remove_connection_async(socket)
25
+ true
26
+ end
27
+
28
+ def close
29
+ server.remove_connection_async(socket)
30
+ true
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PuppetEditorServices
4
+ module Handler
5
+ class Base
6
+ attr_reader :protocol
7
+
8
+ def initialize(protocol)
9
+ @protocol = protocol
10
+ end
11
+
12
+ # @abstract
13
+ def handle(_message, _context = {}); end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puppet_editor_services/handler/base'
4
+ require 'puppet_editor_services/protocol/debug_adapter_messages'
5
+
6
+ module PuppetEditorServices
7
+ module Handler
8
+ class DebugAdapter < ::PuppetEditorServices::Handler::Base
9
+ # options
10
+ # source :request, :notification etc.
11
+ # message JSON Message that caused the error
12
+ # error Actual ruby error
13
+ # @abstract
14
+ def unhandled_exception(error, options)
15
+ PuppetEditorServices.log_message(:error, "Unhandled exception from #{options[:source]}. JSON Message #{options[:message]}: #{error.inspect}\n#{error.backtrace}")
16
+ end
17
+
18
+ # context
19
+ def handle(json_rpc_message, context = {})
20
+ unless json_rpc_message.is_a?(PuppetEditorServices::Protocol::DebugAdapterMessages::Request)
21
+ PuppetEditorServices.log_message(:error, "Unknown JSON RPC message type #{json_rpc_message.class}")
22
+ return false
23
+ end
24
+ handle_request(json_rpc_message, context)
25
+ end
26
+
27
+ # Example Request
28
+ #
29
+ # For a textDocument/completion request
30
+ # def request_textdocument_completion(connection_id, json_rpc_message)
31
+ # ...
32
+ # end
33
+
34
+ private
35
+
36
+ def handle_request(request_message, _context)
37
+ method_name = rpc_name_to_ruby_method_name('request', request_message.command)
38
+ if respond_to?(method_name.intern)
39
+ begin
40
+ result = send(method_name, protocol.connection.id, request_message)
41
+ protocol.encode_and_send(result) unless result.nil?
42
+ rescue NoMethodError, LoadError => e
43
+ unhandled_exception(e, source: :request, message: request_message)
44
+ raise
45
+ rescue StandardError => e
46
+ unhandled_exception(e, source: :request, message: request_message)
47
+ end
48
+ return true
49
+ end
50
+
51
+ # Default processing
52
+ protocol.encode_and_send(::PuppetEditorServices::Protocol::DebugAdapterMessages.reply_error(request_message, "This feature is not supported - Request #{request_message.command}"))
53
+ PuppetEditorServices.log_message(:error, "Unknown request command #{request_message.command}")
54
+
55
+ false
56
+ end
57
+
58
+ def rpc_name_to_ruby_method_name(prefix, rpc_name)
59
+ "#{prefix}_#{rpc_name.tr('/', '_').tr('$', 'dollar').downcase}"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puppet_editor_services/handler/base'
4
+ require 'puppet_editor_services/protocol/json_rpc_messages'
5
+
6
+ module PuppetEditorServices
7
+ module Handler
8
+ class JsonRPC < ::PuppetEditorServices::Handler::Base
9
+ # options
10
+ # source :request, :notification etc.
11
+ # message JSON Message that caused the error
12
+ # error Actual ruby error
13
+ # @abstract
14
+ def unhandled_exception(error, options)
15
+ PuppetEditorServices.log_message(:error, "Unhandled exception from #{options[:source]}. JSON Message #{options[:message]}: #{error.inspect}\n#{error.backtrace}")
16
+ end
17
+
18
+ # context
19
+ # request => original request
20
+ def handle(json_rpc_message, context = {})
21
+ case json_rpc_message
22
+
23
+ when ::PuppetEditorServices::Protocol::JsonRPCMessages::RequestMessage
24
+ return handle_request(json_rpc_message, context)
25
+
26
+ when ::PuppetEditorServices::Protocol::JsonRPCMessages::NotificationMessage
27
+ return handle_notification(json_rpc_message, context)
28
+
29
+ when ::PuppetEditorServices::Protocol::JsonRPCMessages::ResponseMessage
30
+ return handle_response(json_rpc_message, context)
31
+
32
+ else
33
+ PuppetEditorServices.log_message(:error, "Unknown JSON RPC message type #{json_rpc_message.class}")
34
+ end
35
+ false
36
+ end
37
+
38
+ # Example Request
39
+ #
40
+ # For a textDocument/completion request
41
+ # def request_textdocument_completion(connection_id, json_rpc_message)
42
+ # ...
43
+ # end
44
+
45
+ # Example Notification
46
+ # For a workspace/didChangeNotification notification
47
+ # def notification_workspace_didchangeconfiguration(connection_id, json_rpc_message)
48
+ # ...
49
+ # end
50
+
51
+ # Example Response
52
+ # A response to a client/registerCapability request
53
+ # def notification_workspace_didchangeconfiguration(connection_id, json_rpc_message, original_request)
54
+ # ...
55
+ # end
56
+
57
+ private
58
+
59
+ def handle_request(request_message, _context)
60
+ method_name = rpc_name_to_ruby_method_name('request', request_message.rpc_method)
61
+ if respond_to?(method_name.intern)
62
+ begin
63
+ protocol.encode_and_send(
64
+ ::PuppetEditorServices::Protocol::JsonRPCMessages.reply_result(
65
+ request_message, send(method_name, protocol.connection.id, request_message)
66
+ )
67
+ )
68
+ rescue StandardError => e
69
+ unhandled_exception(e, source: :request, message: request_message)
70
+ end
71
+ return true
72
+ end
73
+
74
+ # Default processing
75
+ protocol.encode_and_send(::PuppetEditorServices::Protocol::JsonRPCMessages.reply_method_not_found(request_message))
76
+ if request_message.rpc_method.start_with?('$/')
77
+ PuppetEditorServices.log_message(:debug, "Ignoring RPC request #{request_message.rpc_method}")
78
+ else
79
+ PuppetEditorServices.log_message(:error, "Unknown RPC method #{request_message.rpc_method}")
80
+ end
81
+
82
+ false
83
+ end
84
+
85
+ def handle_notification(notification_message, _context)
86
+ method_name = rpc_name_to_ruby_method_name('notification', notification_message.rpc_method)
87
+ if respond_to?(method_name.intern)
88
+ begin
89
+ send(method_name, protocol.connection.id, notification_message)
90
+ rescue StandardError => e
91
+ unhandled_exception(e, source: :notification, message: notification_message)
92
+ end
93
+ return true
94
+ end
95
+
96
+ # Default processing
97
+ if notification_message.rpc_method.start_with?('$/')
98
+ PuppetEditorServices.log_message(:debug, "Ignoring RPC notification #{notification_message.rpc_method}")
99
+ else
100
+ PuppetEditorServices.log_message(:error, "Unknown RPC notification #{notification_message.rpc_method}")
101
+ end
102
+
103
+ false
104
+ end
105
+
106
+ def handle_response(response_message, context)
107
+ original_request = context[:request]
108
+ return false if original_request.nil?
109
+
110
+ unless response_message.is_successful # rubocop:disable Style/IfUnlessModifier Line is too long otherwise
111
+ PuppetEditorServices.log_message(:error, "Response for method '#{original_request.rpc_method}' with id '#{original_request.id}' failed with #{response_message.error}")
112
+ end
113
+ method_name = rpc_name_to_ruby_method_name('response', original_request.rpc_method)
114
+ if respond_to?(method_name.intern)
115
+ begin
116
+ send(method_name, protocol.connection.id, response_message, original_request)
117
+ rescue StandardError => e
118
+ unhandled_exception(e, source: :response, message: response_message)
119
+ end
120
+ return true
121
+ end
122
+
123
+ # Default processing
124
+ PuppetEditorServices.log_message(:error, "Unknown RPC response for method #{original_request.rpc_method}")
125
+ false
126
+ end
127
+
128
+ def rpc_name_to_ruby_method_name(prefix, rpc_name)
129
+ "#{prefix}_#{rpc_name.tr('/', '_').tr('$', 'dollar').downcase}"
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PuppetEditorServices
4
+ def self.log_message(severity, message)
5
+ return if @logger.nil?
6
+
7
+ case severity
8
+ when :debug
9
+ @logger.debug(message)
10
+ when :info
11
+ @logger.info(message)
12
+ when :warn
13
+ @logger.warn(message)
14
+ when :error
15
+ @logger.error(message)
16
+ when :fatal
17
+ @logger.fatal(message)
18
+ else
19
+ @logger.unknown(message)
20
+ end
21
+ @log_file.fsync unless @log_file.nil?
22
+ end
23
+
24
+ def self.init_logging(options)
25
+ @log_file = nil
26
+ if options[:debug].nil?
27
+ @logger = nil
28
+ elsif (options[:debug].casecmp 'stdout').zero?
29
+ @logger = Logger.new($stdout)
30
+ elsif !options[:debug].to_s.empty?
31
+ # Log to file
32
+ begin
33
+ @log_file = File.open(options[:debug], 'w')
34
+ rescue Errno::ENOENT => e
35
+ # We can't open the log file and we can't log to STDOUT if we're in STDIO mode
36
+ # So log the error to STDERR and disable logging
37
+ $stderr.puts "Error opening log file #{options[:debug]} : #{e}" # rubocop:disable Style/StderrPuts
38
+ @log_file = nil
39
+ return
40
+ end
41
+ @log_file.sync = true
42
+ @logger = Logger.new(@log_file)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PuppetEditorServices
4
+ module Protocol
5
+ class Base
6
+ attr_reader :connection, :handler
7
+
8
+ def initialize(connection)
9
+ @connection = connection
10
+ @handler = connection.server.handler_options[:class].new(self)
11
+ end
12
+
13
+ # @abstract
14
+ def receive_data(data); end
15
+
16
+ def close_connection
17
+ connection.close unless connection.nil?
18
+ end
19
+
20
+ def connection_error?
21
+ return false if connection.nil?
22
+
23
+ connection.error?
24
+ end
25
+ end
26
+ end
27
+ end