rider-server 0.1.0 → 0.1.2

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 (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