rider-server 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.build.yml +3 -3
  3. data/CHANGELOG.md +23 -1
  4. data/COPYING +20 -0
  5. data/README.rdoc +39 -0
  6. data/Rakefile +5 -0
  7. data/exe/rider-server +3 -3
  8. data/lib/rider_server/config.rb +76 -0
  9. data/lib/rider_server/core_ext/array.rb +3 -1
  10. data/lib/rider_server/core_ext/class.rb +5 -0
  11. data/lib/rider_server/core_ext/env.rb +14 -0
  12. data/lib/rider_server/core_ext/hash.rb +3 -1
  13. data/lib/rider_server/core_ext/kernel.rb +5 -0
  14. data/lib/rider_server/core_ext/module.rb +18 -0
  15. data/lib/rider_server/core_ext/object.rb +7 -1
  16. data/lib/rider_server/core_ext/string.rb +3 -1
  17. data/lib/rider_server/core_ext/symbol.rb +3 -1
  18. data/lib/rider_server/exception_extension.rb +2 -0
  19. data/lib/rider_server/inspect.rb +115 -43
  20. data/lib/rider_server/logger.rb +11 -4
  21. data/lib/rider_server/operation.rb +39 -20
  22. data/lib/rider_server/{ops → operations}/clone.rb +3 -2
  23. data/lib/rider_server/{ops → operations}/close.rb +3 -2
  24. data/lib/rider_server/operations/completions.rb +146 -0
  25. data/lib/rider_server/operations/lookup.rb +102 -0
  26. data/lib/rider_server/operations/ls_sessions.rb +51 -0
  27. data/lib/rider_server/operations/toggle_catch_all_exceptions.rb +24 -0
  28. data/lib/rider_server/operations.rb +43 -69
  29. data/lib/rider_server/request.rb +61 -0
  30. data/lib/rider_server/response.rb +10 -2
  31. data/lib/rider_server/server.rb +29 -17
  32. data/lib/rider_server/services/capture_exceptions.rb +18 -2
  33. data/lib/rider_server/services/rails.rb +1 -1
  34. data/lib/rider_server/session.rb +77 -34
  35. data/lib/rider_server/session_operation.rb +17 -0
  36. data/lib/rider_server/session_operations/eval.rb +61 -0
  37. data/lib/rider_server/session_operations/inspect.rb +123 -0
  38. data/lib/rider_server/session_operations/inspect_exception.rb +46 -0
  39. data/lib/rider_server/session_operations/interrupt.rb +29 -0
  40. data/lib/rider_server/session_operations/load_path.rb +19 -0
  41. data/lib/rider_server/session_operations/ls_exceptions.rb +28 -0
  42. data/lib/rider_server/session_operations/ls_services.rb +18 -0
  43. data/lib/rider_server/session_operations/service.rb +42 -0
  44. data/lib/rider_server/session_operations/set_namespace.rb +82 -0
  45. data/lib/rider_server/session_operations/set_namespace_variable.rb +81 -0
  46. data/lib/rider_server/session_operations/stdin.rb +19 -0
  47. data/lib/rider_server/utils.rb +7 -7
  48. data/lib/rider_server/validate/array.rb +32 -0
  49. data/lib/rider_server/validate/base.rb +28 -0
  50. data/lib/rider_server/validate/boolean.rb +47 -0
  51. data/lib/rider_server/validate/hash.rb +32 -0
  52. data/lib/rider_server/validate/integer.rb +56 -0
  53. data/lib/rider_server/validate/predicates.rb +30 -0
  54. data/lib/rider_server/validate/string.rb +60 -0
  55. data/lib/rider_server/validate/symbol.rb +90 -0
  56. data/lib/rider_server/validate.rb +15 -0
  57. data/lib/rider_server/version.rb +1 -1
  58. data/lib/rider_server/workspace.rb +1 -1
  59. data/lib/rider_server.rb +3 -1
  60. metadata +55 -24
  61. data/README.md +0 -44
  62. data/lib/rider_server/ops/completions.rb +0 -100
  63. data/lib/rider_server/ops/eval.rb +0 -62
  64. data/lib/rider_server/ops/inspect.rb +0 -121
  65. data/lib/rider_server/ops/inspect_exception.rb +0 -47
  66. data/lib/rider_server/ops/interrupt.rb +0 -30
  67. data/lib/rider_server/ops/load_path.rb +0 -20
  68. data/lib/rider_server/ops/lookup.rb +0 -83
  69. data/lib/rider_server/ops/ls_exceptions.rb +0 -29
  70. data/lib/rider_server/ops/ls_services.rb +0 -19
  71. data/lib/rider_server/ops/ls_sessions.rb +0 -52
  72. data/lib/rider_server/ops/service.rb +0 -43
  73. data/lib/rider_server/ops/set_namespace.rb +0 -79
  74. data/lib/rider_server/ops/set_namespace_variable.rb +0 -80
  75. data/lib/rider_server/ops/stdin.rb +0 -20
  76. data/lib/rider_server/ops/toggle_catch_all_exceptions.rb +0 -27
@@ -9,6 +9,7 @@
9
9
 
10
10
  require "rider_server/exception_extension"
11
11
  require "rider_server/operations"
12
+ require "rider_server/request"
12
13
  require "rider_server/utils"
13
14
  require "rider_server/logger"
14
15
  require "bencode"
@@ -17,30 +18,28 @@ module RiderServer
17
18
  class Server
18
19
  include RiderServer::Logger
19
20
 
21
+ # The status of the server, either +:running+ or +:stopped+
20
22
  attr_reader :status
21
- attr_reader :listeners
22
23
 
23
- def initialize
24
+ def initialize(config)
25
+ @config = config
24
26
  @status = :stopped
25
- @shutdown_pipe = nil
26
- end
27
27
 
28
- def listen(address, port)
29
- Utils.create_listeners(address, port)
30
- end
31
-
32
- def setup_shutdown_pipe
33
- @shutdown_pipe ||= IO.pipe
28
+ RiderServer::Logger.configure_logger(level: @config.log_level)
34
29
  end
35
30
 
31
+ # Start the servers main event loop. This will bind to the
32
+ # configured host and port, and create threads for sending and
33
+ # recieving requests.
36
34
  def run
37
- socket = listen("127.0.0.1", 7888)
35
+ socket = listen(@config.host, @config.port)
38
36
  request_count = 0
39
37
 
40
38
  responses = Thread::Queue.new
41
- operations = Operations.new(responses)
39
+ operations = RiderServer.create_operation_handler(@config, responses)
42
40
 
43
41
  loop do
42
+ @status = :running
44
43
  client = socket[0].accept
45
44
 
46
45
  request_count += 1
@@ -57,8 +56,8 @@ module RiderServer
57
56
 
58
57
  begin
59
58
  output = response.bencode
60
- rescue StandardError => e
61
- log.error "Error encoding response: #{e}"
59
+ rescue => e
60
+ log.error "Error encoding response: #{e}\n #{e.backtrace.join("\n")}"
62
61
  response = Response.new(response.to_h)
63
62
  response.set("ex", e.inspect)
64
63
  response.set("out", e.full_message)
@@ -67,9 +66,9 @@ module RiderServer
67
66
  end
68
67
 
69
68
  if log.debug?
70
- log.debug "sending response #{response.to_h}"
69
+ log.debug "Sending response #{response.to_h}"
71
70
  else
72
- log.info "sending response #{response.inspect}"
71
+ log.info "Sending response #{response.inspect}"
73
72
  end
74
73
  client.write(output)
75
74
  # Try to allow time for the client to read the response
@@ -92,13 +91,26 @@ module RiderServer
92
91
  operation = parser.parse!
93
92
 
94
93
  log.debug(operation.inspect)
95
- operations.handle(operation)
94
+
95
+ begin
96
+ operations.handle(::RiderServer::Request.new(operation))
97
+ rescue => e
98
+ log.error "Error handling request: #{e}\n #{e.backtrace}"
99
+ end
96
100
  end
97
101
  }
98
102
  threads.each { |thr| thr.join }
99
103
 
100
104
  client.close
105
+ @status = :stopped
101
106
  end
102
107
  end
108
+
109
+ private
110
+
111
+ # Open a TCP server listening on an +address+ and +port+.
112
+ def listen(address, port)
113
+ Utils.create_listeners(address, port)
114
+ end
103
115
  end
104
116
  end
@@ -28,11 +28,27 @@ module RiderServer
28
28
  }
29
29
  end
30
30
 
31
- def self.handle_exception(exception, metadata = {})
31
+ def self.create_exception_wrapper(exception, metadata)
32
+ id = SecureRandom.uuid
33
+ {
34
+ "id" => id,
35
+ "created_at" => DateTime.now,
36
+ "exception" => exception,
37
+ "metadata" => metadata
38
+ }
39
+ end
40
+
41
+ def self.handle_exception(exception, metadata: {})
42
+ wrapped_ex = create_exception_wrapper(exception, metadata)
43
+ # Firstly this needs to generate wrapper for the exception
44
+ # This needs to use push exception
45
+
32
46
  @sessions.each do |session, stream_id|
33
- ex = session.add_exception(stream_id, exception, metadata)
47
+ ex = session.add_wrapped_exception(wrapped_ex)
34
48
  session.response_queue.push(create_response(stream_id, ex))
35
49
  end
50
+
51
+ wrapped_ex
36
52
  end
37
53
 
38
54
  def initialize(session)
@@ -51,7 +51,7 @@ module RiderServer
51
51
  end
52
52
  end
53
53
  rescue => e
54
- @session.push_exception(stream_id, e)
54
+ @session.add_exception(stream_id, e)
55
55
  nputs "Error starting Rails Server: #{e.message}"
56
56
  end
57
57
  end
@@ -15,8 +15,28 @@ require "rider_server/services/rails"
15
15
  require "rider_server/services/capture_io"
16
16
  require "rider_server/services/capture_exceptions"
17
17
  require "rider_server/logger"
18
+ require "rider_server/session_operations/eval"
19
+ require "rider_server/session_operations/inspect"
20
+ require "rider_server/session_operations/inspect_exception"
21
+ require "rider_server/session_operations/interrupt"
22
+ require "rider_server/session_operations/load_path"
23
+ require "rider_server/session_operations/ls_exceptions"
24
+ require "rider_server/session_operations/ls_services"
25
+ require "rider_server/session_operations/service"
26
+ require "rider_server/session_operations/set_namespace"
27
+ require "rider_server/session_operations/set_namespace_variable"
18
28
 
19
29
  module RiderServer
30
+ def self.create_session(config, response_queue, history: [])
31
+ session = Session.new(config, response_queue, history: history)
32
+
33
+ ObjectSpace.each_object(Class).select { |klass| klass < ::RiderServer::Service }.map do |klass, h|
34
+ session.add_service klass
35
+ end
36
+
37
+ session
38
+ end
39
+
20
40
  class Session
21
41
  include RiderServer::Logger
22
42
 
@@ -27,24 +47,17 @@ module RiderServer
27
47
  attr_reader :response_queue
28
48
  attr_reader :history
29
49
 
30
- SERVICES = [
31
- Services::Rails,
32
- Services::CaptureIO,
33
- Services::CaptureExceptions
34
- ]
35
-
36
- def initialize(response_queue, history: [])
50
+ def initialize(config, response_queue, history: [])
37
51
  @id = SecureRandom.uuid
52
+ @config = config
38
53
  @history = history
39
54
  @workspace = Workspace.new
40
55
  @queue = Thread::Queue.new
41
- @exceptions = Utils::FixedArray.new
56
+ @exceptions = Utils::FixedArray.new(max_size: config.exception_history_size)
42
57
  @response_queue = response_queue
43
58
  @exception_queue = Thread::Queue.new
44
59
  @evaluations = {}
45
- @services = SERVICES.each_with_object({}) do |klass, h|
46
- h[klass.service_name] = klass.new(self)
47
- end
60
+ @services = {}
48
61
 
49
62
  # XXX Side effects in initializer, :()
50
63
  start_exception_processing
@@ -56,34 +69,40 @@ module RiderServer
56
69
  end
57
70
  end
58
71
 
72
+ def stdin
73
+ ::STDIN # rubocop:disable Style/GlobalStdStream
74
+ end
75
+
59
76
  def clone
60
- Session.new(@responses_queue, history: @history.clone)
77
+ RiderServer.create_session(@responses_queue, history: @history.clone)
61
78
  end
62
79
 
63
80
  #
64
81
  # Input History
65
82
  #
66
83
 
84
+ # Push an event onto the history stack.
67
85
  def push_history(event)
68
86
  @history.push(event)
69
87
  end
70
88
 
71
- def last_history
72
- @history.last
73
- end
74
-
75
89
  #
76
90
  # Historical Results
77
91
  #
78
92
 
93
+ # Return a Hash containing all historical evaluations.
79
94
  def result_history
80
95
  @result_history ||= {}
81
96
  end
82
97
 
98
+ # Add an execution result to the history. The +evaluation_id+ is
99
+ # the operation id of the evaluation and the +value+ is the result
100
+ # of the evaluation.
83
101
  def add_result(evaluation_id, value)
84
102
  result_history[evaluation_id] = value
85
103
  end
86
104
 
105
+ # Return a historical result of an evaluation by +evaluation_id+.
87
106
  def get_result(evaluation_id)
88
107
  raise "Missing history item #{evaluation_id}." unless result_history.key?(evaluation_id)
89
108
  result_history[evaluation_id]
@@ -93,39 +112,44 @@ module RiderServer
93
112
  # Historical Exceptions
94
113
  #
95
114
 
115
+ # Add an exception to the exception history. +operation_id+ is the
116
+ # id of the request. +exception+ is the exception
117
+ # object. +metadata+ is a Hash containing additional information
118
+ # about the exception.
96
119
  def add_exception(operation_id, exception, metadata = {})
97
- id = SecureRandom.uuid
98
- @exceptions << {
99
- "id" => id,
100
- "operation_id" => operation_id,
101
- "created_at" => DateTime.now,
102
- "exception" => exception,
103
- "metadata" => metadata
104
- }
105
- id
120
+ ex = wrap_exception(operation_id, exception, metadata)
121
+ @exception_queue.push(ex)
122
+ ex
106
123
  end
107
124
 
125
+ # Add an exception that has already been wrapped in metadata.
126
+ # +wrapped_exception+ should be a hash, that has the keys "id",
127
+ # "created_at", "exception", and "metadata"
128
+ def add_wrapped_exception(wrapped_exception)
129
+ @exception_queue.push(wrapped_exception)
130
+ exception
131
+ end
132
+
133
+ # Return an exception by +exception_id+. Raises an exception if
134
+ # the exception doesn't exist.
108
135
  def get_exception(exception_id)
109
136
  exception = @exceptions.find { |item| item["id"] == exception_id }
110
137
  raise "Missing exception #{exception_id}." unless exception
111
138
  exception
112
139
  end
113
140
 
114
- # A threadsafe way to add exceptions
115
- def push_exception(operation_id, exception, metadata = {})
116
- @exception_queue.push([operation_id, exception, metadata])
117
- end
118
-
141
+ # Start a thread to process exceptions from the exception queue.
119
142
  def start_exception_processing
120
143
  return if @exception_processing_thread
121
144
 
122
145
  @exception_processing_thread = Thread.new do
123
146
  loop do
124
- add_exception(*@exception_queue.pop)
147
+ @exceptions << @exception_queue.pop
125
148
  end
126
149
  end
127
150
  end
128
151
 
152
+ # Stop the exception processing thread.
129
153
  def stop_exception_processing
130
154
  @exception_processing_thread.exit
131
155
  @exception_processing_thread = nil
@@ -156,11 +180,17 @@ module RiderServer
156
180
  #
157
181
  # Service control
158
182
  #
183
+
184
+ def add_service(service_class)
185
+ cls = service_class.new(self)
186
+ @services[service_class.service_name] = cls
187
+ end
188
+
159
189
  def list_services
160
- SERVICES.map do |klass|
190
+ @services.map do |name, _|
161
191
  {
162
- "name" => klass.service_name,
163
- "state" => service_state(klass.service_name).to_s
192
+ "name" => name,
193
+ "state" => service_state(name).to_s
164
194
  }
165
195
  end
166
196
  end
@@ -186,5 +216,18 @@ module RiderServer
186
216
  :stopped
187
217
  end
188
218
  end
219
+
220
+ private
221
+
222
+ def wrap_exception(operation_id, exception, metadata = {})
223
+ id = SecureRandom.uuid
224
+ {
225
+ "id" => id,
226
+ "operation_id" => operation_id,
227
+ "created_at" => DateTime.now,
228
+ "exception" => exception,
229
+ "metadata" => metadata
230
+ }
231
+ end
189
232
  end
190
233
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # session_operation.rb -- Base class for operations
5
+ #
6
+ # Author: Russell Sim
7
+ # Copyright (c) 2024 Russell Sim
8
+ # SPDX-License-Identifier: MIT
9
+
10
+ require "rider_server/operation"
11
+
12
+ module RiderServer
13
+ class SessionOperation < Operation
14
+ # Operations registry
15
+ @operations = {}
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ require "rider_server/session_operation"
2
+ require "rider_server/response"
3
+ require "rider_server/utils"
4
+
5
+ module RiderServer
6
+ SessionOperation.define do
7
+ name "eval"
8
+ documentation "Evaluate a string of code"
9
+
10
+ argument :id, :string, "The request id", required: true
11
+ argument :code, :string, "The code to evaluate"
12
+ argument :ns, :string, "The namespace to evaluate the code in"
13
+ argument :file, :string, "The file the code is from"
14
+ argument :line, :integer, "The line number the code is from"
15
+
16
+ def handle(session, operation)
17
+ # TODO should do something if the session is nil
18
+
19
+ response = Response.new(operation)
20
+
21
+ # Abort if there is an evaluation with the same id
22
+ if session.running_evaluation?(operation["id"])
23
+ msg = "Evaluation already in progress for #{operation["id"]}"
24
+ log.warn(msg)
25
+ response.set("value", msg)
26
+ response.status("eval-error", "done")
27
+ send_response(response)
28
+ return
29
+ end
30
+
31
+ session.push_history(operation)
32
+ code = operation["code"]
33
+ ns = operation["ns"]
34
+ file = operation["file"] || ""
35
+ line = operation["line"] || 0
36
+
37
+ eval_thread = Thread.new do
38
+ begin
39
+ value = session.workspace.evaluate(code, ns, file, line)
40
+ response.set("value", Utils.rider_display(value))
41
+ response.set("ns", session.workspace.evaluate("inspect"))
42
+ response.status("done")
43
+ session.add_result(operation["id"], value)
44
+ session.send_response(response)
45
+ rescue EvalInterrupt, ScriptError, StandardError => e
46
+ response.set("ex", e.inspect)
47
+ response.set("ns", session.workspace.evaluate("inspect"))
48
+ response.status("eval-error", "done")
49
+ exception = session.add_exception(operation["id"], e)
50
+ response.set("rider/exception-id", exception["id"])
51
+ session.send_response(response)
52
+ end
53
+
54
+ session.remove_evaluation(operation["id"])
55
+ end
56
+
57
+ session.add_evaluation(operation["id"], eval_thread)
58
+ nil
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,123 @@
1
+ require "rider_server/inspect"
2
+ require "rider_server/operation"
3
+ require "rider_server/response"
4
+ require "rider_server/utils"
5
+
6
+ module RiderServer
7
+ SessionOperation.define do
8
+ name "inspect"
9
+ documentation "Inspect an object"
10
+
11
+ argument :id, :string, "The request id", required: true
12
+ argument :location, :array, "The location of the object to inspect"
13
+
14
+ def handle(session, operation)
15
+ response = Response.new(operation)
16
+ location = operation["location"]
17
+ raise "Location is required" if location.nil? || location.empty?
18
+
19
+ value = traverse_location(location, nil, session)
20
+ response.set("name", Utils.rider_display(value))
21
+
22
+ if value.is_a?(Array)
23
+ value = value.map.with_index do |item, index|
24
+ {
25
+ "name" => item.to_s,
26
+ "value" => Utils.rider_display(item),
27
+ "inspect-location" => "rider_array_item:#{index}"
28
+ }
29
+ end
30
+ response.set("value-array", value)
31
+ elsif value.is_a?(Hash) || value.eql?(::ENV)
32
+ value = value.map do |key, value|
33
+ [
34
+ {
35
+ "name" => key.to_s,
36
+ "value" => Utils.rider_display(key),
37
+ "inspect-location" => "rider_hash_key:#{key.hash}"
38
+ },
39
+ {
40
+ "name" => value.to_s,
41
+ "value" => Utils.rider_display(value),
42
+ "inspect-location" => "rider_hash_value:#{key.hash}"
43
+ }
44
+ ]
45
+ end
46
+ response.set("value-hash", value)
47
+ elsif value.is_a?(String)
48
+ response.set("value", value.inspect)
49
+ elsif value.is_a?(Numeric)
50
+ response.set("value", value.to_s)
51
+ end
52
+
53
+ response.set("inspect-location", location)
54
+
55
+ response.set("class", RiderServer::Inspect.inspect_class(value))
56
+ response.set("singleton-class", RiderServer::Inspect.inspect_singleton_class(value))
57
+ response.set("ancestors", RiderServer::Inspect.inspect_ancestors(value))
58
+ response.set("constants", RiderServer::Inspect.inspect_constants(value))
59
+ response.set("methods", RiderServer::Inspect.inspect_methods(value))
60
+ response.set("instance-variables", RiderServer::Inspect.inspect_instance_variables(value))
61
+ response.set("instance-methods", RiderServer::Inspect.inspect_instance_methods(value))
62
+ response.set("class-variables", RiderServer::Inspect.inspect_class_variables(value))
63
+ response.status("done")
64
+ response
65
+ end
66
+
67
+ def traverse_location(location, ctx, session)
68
+ loc = location.first
69
+ locs = location.drop(1)
70
+
71
+ if locs.empty?
72
+ lookup_object(loc, ctx, session)
73
+ else
74
+ traverse_location(locs, lookup_object(loc, ctx, session), session)
75
+ end
76
+ end
77
+
78
+ def lookup_object(loc, ctx, session)
79
+ lookup, identifier = loc.split(":", 2)
80
+
81
+ case lookup
82
+ when "rider_main"
83
+ "main"
84
+ when "rider_history"
85
+ rider_history(identifier, nil, session)
86
+ when "rider_exception"
87
+ rider_exception(identifier, nil, session)
88
+ when "rider_stackframe_variable"
89
+ frame_id, local_var = identifier.split(":", 2)
90
+ ctx.__rider_bindings_stack[frame_id.to_i].local_variable_get(local_var)
91
+ when "rider_array_item"
92
+ ctx[identifier.to_i]
93
+ when "rider_hash_key"
94
+ hash = identifier.to_i
95
+ ctx.keys.find { |key| key.hash == hash }
96
+ when "rider_hash_value"
97
+ hash = identifier.to_i
98
+ key = ctx.keys.find { |key| key.hash == hash }
99
+ ctx.fetch(key)
100
+ when "toplevel_const_get"
101
+ Object.const_get(identifier)
102
+ when "instance_variable_get"
103
+ ctx.instance_variable_get(identifier)
104
+ when "singleton_class"
105
+ ctx.singleton_class
106
+ when "const_get"
107
+ ctx.const_get(identifier)
108
+ when "ancestor_find"
109
+ ctx.class.ancestors.find { |item| item.to_s == identifier }
110
+ else
111
+ raise "Unknown inspect function: #{lookup}"
112
+ end
113
+ end
114
+
115
+ def rider_history(id, ctx, session)
116
+ session.get_result(id)
117
+ end
118
+
119
+ def rider_exception(id, ctx, session)
120
+ session.get_exception(id)["exception"]
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,46 @@
1
+ require "rider_server/operation"
2
+ require "rider_server/response"
3
+
4
+ module RiderServer
5
+ SessionOperation.define do
6
+ name "inspect-exception"
7
+ documentation "Inspect an exception."
8
+
9
+ argument :id, :string, "The request id", required: true
10
+ argument :"exception-id", :string, "The exception id"
11
+
12
+ def handle(session, operation)
13
+ response = Response.new(operation)
14
+ exception_id = operation["exception-id"]
15
+
16
+ value = session.get_exception(exception_id)
17
+ response.set("inspect-location", value["id"])
18
+ response.set("exception-id", value["id"])
19
+ response.set("source-operation-id", value["operation_id"])
20
+ response.set("created-at", value["created_at"].to_s)
21
+
22
+ exception = value["exception"]
23
+ response.set("value", exception.inspect)
24
+ response.set("stacktrace", encode_stacktrace(exception, exception_id))
25
+
26
+ response.status("done")
27
+ response
28
+ end
29
+
30
+ def encode_stacktrace(exception, exception_id)
31
+ exception.backtrace.zip(exception.__rider_bindings_stack).map.with_index do |(line, frame), frame_id|
32
+ {
33
+ "line" => line,
34
+ "inspect-location" => ["rider_exception:#{exception_id}", "rider_stackframe:#{frame_id}"],
35
+ "frame" => (frame&.local_variables || []).map do |var|
36
+ {
37
+ "name" => var.to_s,
38
+ "value" => Utils.rider_display(frame.local_variable_get(var)),
39
+ "inspect-location" => ["rider_exception:#{exception_id}", "rider_stackframe_variable:#{frame_id}:#{var}"]
40
+ }
41
+ end
42
+ }
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ require "rider_server/operation"
2
+ require "rider_server/response"
3
+
4
+ module RiderServer
5
+ SessionOperation.define do
6
+ name "interrupt"
7
+ documentation "Interrupts the evaluation of a session."
8
+
9
+ argument :id, :string, "The request id", required: true
10
+ argument :"interrupt-id", :string, "The ID of the evaluation to interrupt.", required: true
11
+
12
+ def handle(session, operation)
13
+ # TODO should do something if the session is nil
14
+
15
+ if operation["interrupt-id"].nil? || operation["interrupt-id"].empty?
16
+ if session.evaluations.empty?
17
+ raise ArgumentError, "No evaluations to interrupt"
18
+ end
19
+ session.interrupt_evaluation(session.evaluations.keys.max)
20
+ else
21
+ session.interrupt_evaluation(operation["interrupt-id"])
22
+ end
23
+
24
+ response = Response.new(operation)
25
+ response.status("interrupted", "done")
26
+ response
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require "rider_server/operation"
2
+ require "rider_server/response"
3
+
4
+ module RiderServer
5
+ SessionOperation.define do
6
+ name "load-path"
7
+ documentation "Return the current load path."
8
+
9
+ argument :id, :string, "The request id", required: true
10
+
11
+ def handle(session, operation)
12
+ response = Response.new(operation)
13
+ load_path = session.workspace.evaluate("$LOAD_PATH", "main")
14
+ response.set("load-path", load_path)
15
+ response.status("done")
16
+ response
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ require "rider_server/session_operation"
2
+ require "rider_server/response"
3
+
4
+ module RiderServer
5
+ SessionOperation.define do
6
+ name "ls-exceptions"
7
+ documentation "List all exceptions that exist in the sessions cache."
8
+
9
+ argument :id, :string, "The request id", required: true
10
+
11
+ def handle(session, operation)
12
+ response = Response.new(operation)
13
+
14
+ exceptions = session.exceptions.map do |item|
15
+ {
16
+ "id" => item["id"],
17
+ "operation-id" => item["operation_id"],
18
+ "created-at" => item["created_at"].iso8601,
19
+ "exception" => item["exception"].inspect
20
+ }
21
+ end
22
+
23
+ response.set("exceptions", exceptions)
24
+ response.status("done")
25
+ response
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ require "rider_server/operation"
2
+ require "rider_server/response"
3
+
4
+ module RiderServer
5
+ SessionOperation.define do
6
+ name "ls-services"
7
+ documentation "List all services."
8
+
9
+ argument :id, :string, "The request id", required: true
10
+
11
+ def handle(session, operation)
12
+ response = Response.new(operation)
13
+ response.set("services", session.list_services)
14
+ response.status("done")
15
+ response
16
+ end
17
+ end
18
+ end