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