rider-server 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.build.yml +23 -0
- data/.ruby-version +1 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/README.md +44 -0
- data/Rakefile +12 -0
- data/exe/rider-server +11 -0
- data/lib/rider_server/core_ext/array.rb +32 -0
- data/lib/rider_server/core_ext/hash.rb +14 -0
- data/lib/rider_server/core_ext/object.rb +18 -0
- data/lib/rider_server/core_ext/string.rb +18 -0
- data/lib/rider_server/core_ext/symbol.rb +14 -0
- data/lib/rider_server/errors.rb +16 -0
- data/lib/rider_server/exception_extension.rb +34 -0
- data/lib/rider_server/inspect.rb +148 -0
- data/lib/rider_server/logger.rb +13 -0
- data/lib/rider_server/operation.rb +69 -0
- data/lib/rider_server/operations.rb +136 -0
- data/lib/rider_server/ops/clone.rb +32 -0
- data/lib/rider_server/ops/close.rb +25 -0
- data/lib/rider_server/ops/completions.rb +100 -0
- data/lib/rider_server/ops/eval.rb +62 -0
- data/lib/rider_server/ops/inspect.rb +121 -0
- data/lib/rider_server/ops/inspect_exception.rb +47 -0
- data/lib/rider_server/ops/interrupt.rb +30 -0
- data/lib/rider_server/ops/load_path.rb +20 -0
- data/lib/rider_server/ops/lookup.rb +83 -0
- data/lib/rider_server/ops/ls_exceptions.rb +29 -0
- data/lib/rider_server/ops/ls_services.rb +19 -0
- data/lib/rider_server/ops/ls_sessions.rb +52 -0
- data/lib/rider_server/ops/service.rb +43 -0
- data/lib/rider_server/ops/set_namespace.rb +79 -0
- data/lib/rider_server/ops/set_namespace_variable.rb +80 -0
- data/lib/rider_server/ops/stdin.rb +20 -0
- data/lib/rider_server/ops/toggle_catch_all_exceptions.rb +27 -0
- data/lib/rider_server/response.rb +69 -0
- data/lib/rider_server/server.rb +104 -0
- data/lib/rider_server/service.rb +20 -0
- data/lib/rider_server/services/capture_exceptions.rb +62 -0
- data/lib/rider_server/services/capture_io.rb +302 -0
- data/lib/rider_server/services/rails.rb +129 -0
- data/lib/rider_server/session.rb +190 -0
- data/lib/rider_server/transports/bencode.rb +0 -0
- data/lib/rider_server/utils.rb +63 -0
- data/lib/rider_server/version.rb +12 -0
- data/lib/rider_server/workspace.rb +111 -0
- data/lib/rider_server.rb +5 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 302928be71e4f0608534e86f87c555a0f3507004c93c058947b74d480cfde558
|
4
|
+
data.tar.gz: 80707ddff979bb2a92f7f696dcbc44ac68830d56dffa11cfc021aa5eec06d743
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f9fcc56b8cbceaa6df781155af166873e66c0bfe1261041b6667759dfc5eb56c3c9dfd6943b45e1e7f302cb0737e21da048ba399f837dec4a77416cb7af037bf
|
7
|
+
data.tar.gz: 74527b4e988b97b6ed527530bbdef94cc6b48776c74fef12930dbf70a59c648209f3afa615ebb835861acba0b0eba70884107268b65e7aa12da0adb7b63040f8
|
data/.build.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
image: debian/stable
|
2
|
+
sources:
|
3
|
+
- https://git.sr.ht/~rsl/rider
|
4
|
+
packages:
|
5
|
+
- bundler
|
6
|
+
- curl
|
7
|
+
- git-extras
|
8
|
+
- ruby-full
|
9
|
+
- ruby-dev
|
10
|
+
- zlib1g-dev
|
11
|
+
tasks:
|
12
|
+
- lint: |
|
13
|
+
cd rider
|
14
|
+
bundle install --path="../.gems"
|
15
|
+
bundle exec rake standard
|
16
|
+
- test: |
|
17
|
+
cd rider
|
18
|
+
bundle install --path="../.gems"
|
19
|
+
bundle exec rake test
|
20
|
+
triggers:
|
21
|
+
- action: email
|
22
|
+
condition: failure
|
23
|
+
to: "Russell Sim <rsl@simopolis.xyz>"
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.1.6
|
data/.standard.yml
ADDED
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# RIDER -- RIDER Interactive Development Environment for Ruby
|
2
|
+
|
3
|
+
RIDER Server is the server component of the RIDER development
|
4
|
+
environment.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
TODO: Replace
|
9
|
+
`UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG`
|
10
|
+
with your gem name right after releasing it to RubyGems.org. Please do
|
11
|
+
not do it earlier due to security reasons. Alternatively, replace this
|
12
|
+
section with instructions to install your gem from git if you don't
|
13
|
+
plan to release to RubyGems.org.
|
14
|
+
|
15
|
+
Install the gem and add to the application's Gemfile by executing:
|
16
|
+
|
17
|
+
$ bundle add rider-server
|
18
|
+
|
19
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
20
|
+
|
21
|
+
$ gem install rider-server
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install
|
30
|
+
dependencies. Then, run `rake test` to run the tests. You can also run
|
31
|
+
`bin/console` for an interactive prompt that will allow you to
|
32
|
+
experiment.
|
33
|
+
|
34
|
+
To install this gem onto your local machine, run `bundle exec rake
|
35
|
+
install`. To release a new version, update the version number in
|
36
|
+
`version.rb`, and then run `bundle exec rake release`, which will
|
37
|
+
create a git tag for the version, push git commits and the created
|
38
|
+
tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
Bug reports https://todo.sr.ht/~rsl/rider
|
43
|
+
|
44
|
+
Support or discussion https://lists.sr.ht/~rsl/rider-devel
|
data/Rakefile
ADDED
data/exe/rider-server
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Author: Russell Sim
|
3
|
+
# Copyright (c) 2024 Russell Sim
|
4
|
+
# SPDX-License-Identifier: MIT
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
7
|
+
|
8
|
+
require "rider_server/server"
|
9
|
+
|
10
|
+
server = RiderServer::Server.new
|
11
|
+
server.run
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# array.rb -- Array extensions
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
class Array
|
11
|
+
def rider_inspect
|
12
|
+
max_length = 50
|
13
|
+
sample = +""
|
14
|
+
|
15
|
+
dup.slice(0, 3).each do |item|
|
16
|
+
str = item.inspect
|
17
|
+
remaining = max_length - (sample.length + str.length)
|
18
|
+
|
19
|
+
# Truncate the string, and preserve any terminators
|
20
|
+
if sample.length >= max_length
|
21
|
+
# Ignore item
|
22
|
+
elsif remaining < 0
|
23
|
+
terminator = ["]", '"', "'", ">"].member?(str[-1]) ? str[-1] : ""
|
24
|
+
sample << (str.dup[0, max_length] + "..." + terminator)
|
25
|
+
else
|
26
|
+
sample << str.dup
|
27
|
+
sample << ", "
|
28
|
+
end
|
29
|
+
end
|
30
|
+
"#<#{self.class}: [#{sample}] size: #{length}>"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# hash.rb -- Hash extensions
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
class Hash
|
11
|
+
def rider_inspect
|
12
|
+
"#<#{self.class}: #{length} items}>"
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# object.rb -- Object class extensions
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
class Object
|
11
|
+
def rider_inspect
|
12
|
+
if defined?(inspect) && method(:inspect).owner != Object && method(:inspect).owner != Kernel
|
13
|
+
inspect
|
14
|
+
else
|
15
|
+
"#<#{self.class} #{object_id}>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# string.rb -- String extensions
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
class String
|
11
|
+
def rider_inspect
|
12
|
+
if length <= 50
|
13
|
+
"#<String #{inspect}>"
|
14
|
+
else
|
15
|
+
"#<String \"#{self[0, 50]}...\" #{length - 50} more characters>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# errors.rb -- Errors
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
module RiderServer
|
11
|
+
class Error < StandardError; end
|
12
|
+
|
13
|
+
class EvalInterrupt < Error; end
|
14
|
+
|
15
|
+
class ModuleLookupError < Error; end
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# exception_extension.rb -- Add stackframes to exceptions
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
require "binding_of_caller"
|
11
|
+
|
12
|
+
module RiderServer
|
13
|
+
module ExceptionExtension
|
14
|
+
INPUT_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$}
|
15
|
+
|
16
|
+
def set_backtrace(...)
|
17
|
+
if caller.none? { |loc| loc.match(INPUT_FORMAT) && Regexp.last_match(1) == __FILE__ }
|
18
|
+
@__rider_bindings_stack = ::Kernel.binding.callers.drop(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def __rider_bindings_stack
|
25
|
+
@__rider_bindings_stack || []
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
unless ::Exception.included_modules.include?(RiderServer::ExceptionExtension)
|
31
|
+
class ::Exception
|
32
|
+
prepend RiderServer::ExceptionExtension
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# inspect.rb -- Methods to help inspect objects
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
require "rider_server/utils"
|
11
|
+
|
12
|
+
module RiderServer
|
13
|
+
module Inspect
|
14
|
+
|
15
|
+
def self.safely_eval(string, file, line)
|
16
|
+
code = <<~HEREDOC
|
17
|
+
begin
|
18
|
+
#{string}
|
19
|
+
rescue StandardError => e
|
20
|
+
e
|
21
|
+
end
|
22
|
+
HEREDOC
|
23
|
+
eval(code, TOPLEVEL_BINDING, file, line) # rubocop:disable Security/Eval
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.class(obj)
|
27
|
+
klass = obj.class
|
28
|
+
{
|
29
|
+
"name" => klass.to_s,
|
30
|
+
"value" => Utils.rider_inspect(safely_eval("Object.const_get('#{klass}')", __FILE__, __LINE__)),
|
31
|
+
"inspect-location" => "toplevel_const_get:#{klass.inspect}",
|
32
|
+
"source-location" => safely_eval("Object.const_source_location('#{klass}')", __FILE__, __LINE__) || []
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.ancestors(obj)
|
37
|
+
# Look for instance ancestors on the class.
|
38
|
+
obj = obj.class if !obj.respond_to?(:ancestors) && obj.class.respond_to?(:ancestors)
|
39
|
+
|
40
|
+
if obj.class.respond_to?(:ancestors)
|
41
|
+
obj.class.ancestors.map do |item|
|
42
|
+
{
|
43
|
+
"name" => item.to_s,
|
44
|
+
"value" => Utils.rider_inspect(item),
|
45
|
+
"inspect-location" => "ancestor_find:#{item}",
|
46
|
+
"source-location" => safely_eval("Object.const_source_location('#{item}')", __FILE__, __LINE__) || []
|
47
|
+
}
|
48
|
+
end
|
49
|
+
else
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.constants(obj)
|
55
|
+
if obj.respond_to?(:constants)
|
56
|
+
constants = safely_eval("#{obj.inspect}.constants", __FILE__, __LINE__)
|
57
|
+
return [] if constants.nil? # Eigen classes have no constants
|
58
|
+
constants.map do |item|
|
59
|
+
{
|
60
|
+
"name" => item.to_s,
|
61
|
+
"value" => Utils.rider_inspect(safely_eval("#{obj.inspect}.const_get('#{item}')", __FILE__, __LINE__)),
|
62
|
+
"inspect-location" => "const_get:#{obj.inspect}::#{item}",
|
63
|
+
"source-location" => safely_eval("#{obj.inspect}.const_source_location('#{item}')", __FILE__, __LINE__) || []
|
64
|
+
}
|
65
|
+
end.sort_by { |hash| hash["name"] }
|
66
|
+
else
|
67
|
+
[]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.describe_method(method)
|
72
|
+
{
|
73
|
+
"name" => method.name.to_s,
|
74
|
+
"value" => Utils.rider_inspect(method),
|
75
|
+
"visibility" => if method.private?
|
76
|
+
":private"
|
77
|
+
elsif method.protected?
|
78
|
+
":protected"
|
79
|
+
elsif method.public?
|
80
|
+
":public"
|
81
|
+
else
|
82
|
+
":unknown"
|
83
|
+
end,
|
84
|
+
"owner" => method.owner.inspect,
|
85
|
+
"source-location" => method.source_location || [],
|
86
|
+
"parameters" => method.parameters.map { |subarray| subarray.map(&:to_s) }
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.methods(obj)
|
91
|
+
if obj.respond_to?(:methods)
|
92
|
+
obj.methods.map do |name|
|
93
|
+
describe_method(obj.method(name))
|
94
|
+
end
|
95
|
+
else
|
96
|
+
[]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.instance_methods(obj)
|
101
|
+
if obj.respond_to?(:instance_methods)
|
102
|
+
obj.instance_methods.map do |item|
|
103
|
+
describe_method(obj.instance_method(item))
|
104
|
+
end
|
105
|
+
else
|
106
|
+
[]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.instance_variables(obj)
|
111
|
+
if obj.respond_to?(:instance_variables)
|
112
|
+
obj.instance_variables.map do |item|
|
113
|
+
[
|
114
|
+
{
|
115
|
+
"name" => item.to_s
|
116
|
+
},
|
117
|
+
{
|
118
|
+
"name" => obj.instance_variable_get(item).to_s,
|
119
|
+
"value" => Utils.rider_inspect(obj.instance_variable_get(item)),
|
120
|
+
"inspect-location" => "instance_variable_get:#{item}"
|
121
|
+
}
|
122
|
+
]
|
123
|
+
end
|
124
|
+
else
|
125
|
+
[]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.class_variables(obj)
|
130
|
+
if obj.respond_to?(:class_variables)
|
131
|
+
obj.class_variables.map do |item|
|
132
|
+
[
|
133
|
+
{
|
134
|
+
"name" => item.to_s
|
135
|
+
},
|
136
|
+
{
|
137
|
+
"name" => obj.class_variable_get(item).to_s,
|
138
|
+
"value" => Utils.rider_inspect(obj.class_variable_get(item)),
|
139
|
+
"inspect-location" => "class_variable_get:#{item}"
|
140
|
+
}
|
141
|
+
]
|
142
|
+
end
|
143
|
+
else
|
144
|
+
[]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# 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/logger"
|
11
|
+
|
12
|
+
module RiderServer
|
13
|
+
class Operation
|
14
|
+
include RiderServer::Logger
|
15
|
+
|
16
|
+
attr_reader :documentation, :arguments, :controller
|
17
|
+
def self.operation_name
|
18
|
+
name.split("::").last.gsub(/(.)([A-Z])/, '\1_\2').downcase
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.documentation(desc)
|
22
|
+
@documentation = desc
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.argument(name, type, description, required: false)
|
26
|
+
@arguments ||= []
|
27
|
+
|
28
|
+
raise ArgumentError, "Invalid argument type #{type}" \
|
29
|
+
unless [:string, :integer, :array].include?(type)
|
30
|
+
|
31
|
+
@arguments << {name: name, type: type, required: required, description: description}
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(controller)
|
35
|
+
@controller = controller
|
36
|
+
@documentation = self.class.instance_variable_get(:@documentation) || ""
|
37
|
+
@arguments = self.class.instance_variable_get(:@arguments) || []
|
38
|
+
raise ArgumentError, "Operation must have a documentation string" if @documentation.empty?
|
39
|
+
raise ArgumentError, "Operation must have at least one argument" if @arguments.empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_response(operation)
|
43
|
+
Utils.create_response(operation)
|
44
|
+
end
|
45
|
+
|
46
|
+
def send_response(response)
|
47
|
+
controller.send_response(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_request!(request)
|
51
|
+
@arguments.each do |arg|
|
52
|
+
# Skip optional arguments
|
53
|
+
next if !arg[:required] && !request.key?(arg[:name])
|
54
|
+
|
55
|
+
name = arg[:name].to_s
|
56
|
+
|
57
|
+
if arg[:type] == :integer
|
58
|
+
request[name] = Integer(request[name])
|
59
|
+
elsif arg[:type] == :string
|
60
|
+
request[name] = String(request[name])
|
61
|
+
elsif arg[:type] == :array && request[name].is_a?(Array)
|
62
|
+
# pass, the type is correct
|
63
|
+
else
|
64
|
+
raise ArgumentError, "Invalid argument type #{arg[:type]}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# operations.rb -- Handle all the nRepl op codes
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
require "rider_server/logger"
|
11
|
+
require "rider_server/session"
|
12
|
+
require "rider_server/errors"
|
13
|
+
require "rider_server/response"
|
14
|
+
require "rider_server/core_ext/array"
|
15
|
+
require "rider_server/core_ext/hash"
|
16
|
+
require "rider_server/core_ext/object"
|
17
|
+
require "rider_server/core_ext/string"
|
18
|
+
require "rider_server/core_ext/symbol"
|
19
|
+
require "rider_server/ops/clone"
|
20
|
+
require "rider_server/ops/close"
|
21
|
+
require "rider_server/ops/completions"
|
22
|
+
require "rider_server/ops/eval"
|
23
|
+
require "rider_server/ops/inspect"
|
24
|
+
require "rider_server/ops/inspect_exception"
|
25
|
+
require "rider_server/ops/interrupt"
|
26
|
+
require "rider_server/ops/load_path"
|
27
|
+
require "rider_server/ops/lookup"
|
28
|
+
require "rider_server/ops/ls_exceptions"
|
29
|
+
require "rider_server/ops/ls_services"
|
30
|
+
require "rider_server/ops/ls_sessions"
|
31
|
+
require "rider_server/ops/service"
|
32
|
+
require "rider_server/ops/set_namespace"
|
33
|
+
require "rider_server/ops/set_namespace_variable"
|
34
|
+
require "rider_server/ops/toggle_catch_all_exceptions"
|
35
|
+
|
36
|
+
module RiderServer
|
37
|
+
class Operations
|
38
|
+
include RiderServer::Logger
|
39
|
+
|
40
|
+
attr_reader :executing_requests
|
41
|
+
attr_reader :sessions
|
42
|
+
attr_reader :stdin, :stdout, :stderr
|
43
|
+
attr_reader :response_queue
|
44
|
+
attr_accessor :sessions_catching_exceptions
|
45
|
+
|
46
|
+
OPERATIONS = [
|
47
|
+
Ops::Clone,
|
48
|
+
Ops::Close,
|
49
|
+
Ops::Completions,
|
50
|
+
Ops::Eval,
|
51
|
+
Ops::Inspect,
|
52
|
+
Ops::InspectException,
|
53
|
+
Ops::Interrupt,
|
54
|
+
Ops::LoadPath,
|
55
|
+
Ops::Lookup,
|
56
|
+
Ops::LsExceptions,
|
57
|
+
Ops::LsServices,
|
58
|
+
Ops::LsSessions,
|
59
|
+
Ops::Service,
|
60
|
+
Ops::SetNamespace,
|
61
|
+
Ops::SetNamespaceVariable,
|
62
|
+
Ops::ToggleCatchAllExceptions
|
63
|
+
]
|
64
|
+
|
65
|
+
def initialize(response_queue)
|
66
|
+
@sessions = {}
|
67
|
+
@response_queue = response_queue
|
68
|
+
@executing_requests = []
|
69
|
+
@operations = OPERATIONS.each_with_object({}) do |klass, h|
|
70
|
+
h[klass.operation_name] = klass.new(self)
|
71
|
+
end
|
72
|
+
@sessions_catching_exceptions = []
|
73
|
+
end
|
74
|
+
|
75
|
+
def send_response(response)
|
76
|
+
if response
|
77
|
+
@response_queue.push(response)
|
78
|
+
if response.done?
|
79
|
+
@executing_requests.delete(response.id)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def handle(operation)
|
85
|
+
session = nil
|
86
|
+
|
87
|
+
session_id = operation["session"]
|
88
|
+
op = operation["op"].tr("-", "_")
|
89
|
+
log.info("Handling operation '#{operation}'")
|
90
|
+
session = get_session(session_id)
|
91
|
+
@executing_requests << operation["id"]
|
92
|
+
if @operations.key? op
|
93
|
+
@operations[op].validate_request!(operation)
|
94
|
+
send_response(@operations[op].handle(session, operation))
|
95
|
+
else
|
96
|
+
log.warn("Unknown operation '#{op}' requested")
|
97
|
+
response = Response.new(operation)
|
98
|
+
response.status "unknown-op", "done"
|
99
|
+
send_response(response)
|
100
|
+
end
|
101
|
+
rescue ScriptError, StandardError => e
|
102
|
+
response = Response.new(operation)
|
103
|
+
response.set("ex", e.inspect)
|
104
|
+
response.set("out", e.full_message)
|
105
|
+
response.status("eval-error", "done")
|
106
|
+
if session
|
107
|
+
exception_id = session.add_exception(operation["id"], e)
|
108
|
+
response.set("rider/exception-id", exception_id)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Broadcast the exception to sessions that are listening
|
112
|
+
@sessions_catching_exceptions.each do |s|
|
113
|
+
next if session == s
|
114
|
+
@sessions[s]&.add_exception(operation["id"], e)
|
115
|
+
end
|
116
|
+
send_response(response)
|
117
|
+
end
|
118
|
+
|
119
|
+
def new_session
|
120
|
+
Session.new(@response_queue)
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_session(id)
|
124
|
+
return nil unless id
|
125
|
+
@sessions[id]
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_session(session)
|
129
|
+
@sessions[session.id] = session
|
130
|
+
end
|
131
|
+
|
132
|
+
def delete_session(session_id)
|
133
|
+
@sessions.delete(session_id)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "rider_server/operation"
|
2
|
+
require "rider_server/response"
|
3
|
+
|
4
|
+
module RiderServer
|
5
|
+
module Ops
|
6
|
+
class Clone < Operation
|
7
|
+
documentation "Clone a session"
|
8
|
+
|
9
|
+
argument :id, :string, "The request id", required: true
|
10
|
+
argument :session, :string, "The session to clone"
|
11
|
+
|
12
|
+
# Handle the clone operation, session will be nil
|
13
|
+
def handle(session, operation)
|
14
|
+
response = Response.new(operation)
|
15
|
+
|
16
|
+
# Clone a specific session if specified
|
17
|
+
storage_session = operation["session"]
|
18
|
+
new_session = if storage_session
|
19
|
+
controller.get_session(storage_session).clone
|
20
|
+
else
|
21
|
+
controller.new_session
|
22
|
+
end
|
23
|
+
|
24
|
+
controller.add_session(new_session)
|
25
|
+
|
26
|
+
response.set("new-session", new_session.id)
|
27
|
+
response.status("done")
|
28
|
+
response
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|