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.
- checksums.yaml +4 -4
- data/.build.yml +3 -3
- data/CHANGELOG.md +23 -1
- data/COPYING +20 -0
- data/README.rdoc +39 -0
- data/Rakefile +5 -0
- data/exe/rider-server +3 -3
- data/lib/rider_server/config.rb +76 -0
- data/lib/rider_server/core_ext/array.rb +3 -1
- data/lib/rider_server/core_ext/class.rb +5 -0
- data/lib/rider_server/core_ext/env.rb +14 -0
- data/lib/rider_server/core_ext/hash.rb +3 -1
- data/lib/rider_server/core_ext/kernel.rb +5 -0
- data/lib/rider_server/core_ext/module.rb +18 -0
- data/lib/rider_server/core_ext/object.rb +7 -1
- data/lib/rider_server/core_ext/string.rb +3 -1
- data/lib/rider_server/core_ext/symbol.rb +3 -1
- data/lib/rider_server/exception_extension.rb +2 -0
- data/lib/rider_server/inspect.rb +115 -43
- data/lib/rider_server/logger.rb +11 -4
- data/lib/rider_server/operation.rb +39 -20
- data/lib/rider_server/{ops → operations}/clone.rb +3 -2
- data/lib/rider_server/{ops → operations}/close.rb +3 -2
- data/lib/rider_server/operations/completions.rb +146 -0
- data/lib/rider_server/operations/lookup.rb +102 -0
- data/lib/rider_server/operations/ls_sessions.rb +51 -0
- data/lib/rider_server/operations/toggle_catch_all_exceptions.rb +24 -0
- data/lib/rider_server/operations.rb +43 -69
- data/lib/rider_server/request.rb +61 -0
- data/lib/rider_server/response.rb +10 -2
- data/lib/rider_server/server.rb +29 -17
- data/lib/rider_server/services/capture_exceptions.rb +18 -2
- data/lib/rider_server/services/rails.rb +1 -1
- data/lib/rider_server/session.rb +77 -34
- data/lib/rider_server/session_operation.rb +17 -0
- data/lib/rider_server/session_operations/eval.rb +61 -0
- data/lib/rider_server/session_operations/inspect.rb +123 -0
- data/lib/rider_server/session_operations/inspect_exception.rb +46 -0
- data/lib/rider_server/session_operations/interrupt.rb +29 -0
- data/lib/rider_server/session_operations/load_path.rb +19 -0
- data/lib/rider_server/session_operations/ls_exceptions.rb +28 -0
- data/lib/rider_server/session_operations/ls_services.rb +18 -0
- data/lib/rider_server/session_operations/service.rb +42 -0
- data/lib/rider_server/session_operations/set_namespace.rb +82 -0
- data/lib/rider_server/session_operations/set_namespace_variable.rb +81 -0
- data/lib/rider_server/session_operations/stdin.rb +19 -0
- data/lib/rider_server/utils.rb +7 -7
- data/lib/rider_server/validate/array.rb +32 -0
- data/lib/rider_server/validate/base.rb +28 -0
- data/lib/rider_server/validate/boolean.rb +47 -0
- data/lib/rider_server/validate/hash.rb +32 -0
- data/lib/rider_server/validate/integer.rb +56 -0
- data/lib/rider_server/validate/predicates.rb +30 -0
- data/lib/rider_server/validate/string.rb +60 -0
- data/lib/rider_server/validate/symbol.rb +90 -0
- data/lib/rider_server/validate.rb +15 -0
- data/lib/rider_server/version.rb +1 -1
- data/lib/rider_server/workspace.rb +1 -1
- data/lib/rider_server.rb +3 -1
- metadata +55 -24
- data/README.md +0 -44
- data/lib/rider_server/ops/completions.rb +0 -100
- data/lib/rider_server/ops/eval.rb +0 -62
- data/lib/rider_server/ops/inspect.rb +0 -121
- data/lib/rider_server/ops/inspect_exception.rb +0 -47
- data/lib/rider_server/ops/interrupt.rb +0 -30
- data/lib/rider_server/ops/load_path.rb +0 -20
- data/lib/rider_server/ops/lookup.rb +0 -83
- data/lib/rider_server/ops/ls_exceptions.rb +0 -29
- data/lib/rider_server/ops/ls_services.rb +0 -19
- data/lib/rider_server/ops/ls_sessions.rb +0 -52
- data/lib/rider_server/ops/service.rb +0 -43
- data/lib/rider_server/ops/set_namespace.rb +0 -79
- data/lib/rider_server/ops/set_namespace_variable.rb +0 -80
- data/lib/rider_server/ops/stdin.rb +0 -20
- data/lib/rider_server/ops/toggle_catch_all_exceptions.rb +0 -27
data/lib/rider_server/server.rb
CHANGED
@@ -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
|
-
|
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(
|
35
|
+
socket = listen(@config.host, @config.port)
|
38
36
|
request_count = 0
|
39
37
|
|
40
38
|
responses = Thread::Queue.new
|
41
|
-
operations =
|
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
|
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 "
|
69
|
+
log.debug "Sending response #{response.to_h}"
|
71
70
|
else
|
72
|
-
log.info "
|
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
|
-
|
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.
|
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.
|
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)
|
data/lib/rider_server/session.rb
CHANGED
@@ -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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
98
|
-
@
|
99
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
190
|
+
@services.map do |name, _|
|
161
191
|
{
|
162
|
-
"name" =>
|
163
|
-
"state" => service_state(
|
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
|