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
@@ -13,38 +13,57 @@ module RiderServer
|
|
13
13
|
class Operation
|
14
14
|
include RiderServer::Logger
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
# Operations registry
|
17
|
+
@operations = {}
|
18
|
+
class << self
|
19
|
+
attr_reader :operations
|
19
20
|
end
|
20
21
|
|
21
|
-
def self.
|
22
|
-
@
|
22
|
+
def self.handles?(request)
|
23
|
+
@operations.key? request.op
|
23
24
|
end
|
24
25
|
|
25
|
-
def self.
|
26
|
-
|
26
|
+
def self.handle(context, request)
|
27
|
+
operation = @operations[request.op]
|
28
|
+
operation.validate_request!(request)
|
29
|
+
operation.handle(context, request)
|
30
|
+
end
|
27
31
|
|
28
|
-
|
29
|
-
|
32
|
+
def self.define(&block)
|
33
|
+
instance = new
|
34
|
+
instance.instance_eval(&block)
|
35
|
+
raise ArgumentError, "Operation #{self} must have a name" if instance.name.empty?
|
36
|
+
raise ArgumentError, "Operation #{self} must have a documentation string" if instance.documentation.empty?
|
37
|
+
raise ArgumentError, "Operation #{self} must have at least one argument" if instance.arguments.empty?
|
38
|
+
@operations[instance.name] = instance
|
39
|
+
instance
|
40
|
+
end
|
30
41
|
|
31
|
-
|
42
|
+
attr_reader :arguments
|
43
|
+
|
44
|
+
def documentation(value = nil)
|
45
|
+
@documentation = value if value
|
46
|
+
@documentation
|
32
47
|
end
|
33
48
|
|
34
|
-
def
|
35
|
-
@
|
36
|
-
@
|
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?
|
49
|
+
def name(value = nil)
|
50
|
+
@name = value if value
|
51
|
+
@name
|
40
52
|
end
|
41
53
|
|
42
|
-
def
|
43
|
-
|
54
|
+
def initialize
|
55
|
+
@name = ""
|
56
|
+
@arguments = []
|
57
|
+
@documentation = ""
|
44
58
|
end
|
45
59
|
|
46
|
-
def
|
47
|
-
|
60
|
+
def argument(name, type, description, required: false)
|
61
|
+
@arguments ||= []
|
62
|
+
|
63
|
+
raise ArgumentError, "Invalid argument type #{type}" \
|
64
|
+
unless [:string, :integer, :array].include?(type)
|
65
|
+
|
66
|
+
@arguments << {name: name, type: type, required: required, description: description}
|
48
67
|
end
|
49
68
|
|
50
69
|
def validate_request!(request)
|
@@ -3,14 +3,15 @@ require "rider_server/response"
|
|
3
3
|
|
4
4
|
module RiderServer
|
5
5
|
module Ops
|
6
|
-
|
6
|
+
Operation.define do
|
7
|
+
name "clone"
|
7
8
|
documentation "Clone a session"
|
8
9
|
|
9
10
|
argument :id, :string, "The request id", required: true
|
10
11
|
argument :session, :string, "The session to clone"
|
11
12
|
|
12
13
|
# Handle the clone operation, session will be nil
|
13
|
-
def handle(
|
14
|
+
def handle(controller, operation)
|
14
15
|
response = Response.new(operation)
|
15
16
|
|
16
17
|
# Clone a specific session if specified
|
@@ -3,14 +3,15 @@ require "rider_server/response"
|
|
3
3
|
|
4
4
|
module RiderServer
|
5
5
|
module Ops
|
6
|
-
|
6
|
+
Close = Operation.define do
|
7
|
+
name "close"
|
7
8
|
documentation "Close a specific session."
|
8
9
|
|
9
10
|
argument :id, :string, "The request id", required: true
|
10
11
|
argument :session, :string, "The session to close", required: true
|
11
12
|
|
12
13
|
# Handle the close operation, session will be nil
|
13
|
-
def handle(
|
14
|
+
def handle(controller, operation)
|
14
15
|
response = Response.new(operation)
|
15
16
|
|
16
17
|
session_id = operation["session"]
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require "rider_server/operation"
|
2
|
+
require "rider_server/response"
|
3
|
+
require "rider_server/inspect"
|
4
|
+
require "rider_server/workspace"
|
5
|
+
|
6
|
+
module RiderServer
|
7
|
+
Operation.define do
|
8
|
+
name "completions"
|
9
|
+
documentation "Get completions for a given prefix"
|
10
|
+
|
11
|
+
argument :id, :string, "The request id", required: true
|
12
|
+
argument :prefix, :string, "The prefix to complete", required: true
|
13
|
+
argument :complete_fn, :string, "What completion function to use, top-level, module, method or singleton-method"
|
14
|
+
argument :ns, :string, "The namespace to search for completions"
|
15
|
+
|
16
|
+
@workspace = Workspace.new
|
17
|
+
|
18
|
+
def handle(controller, operation)
|
19
|
+
response = Response.new(operation)
|
20
|
+
|
21
|
+
prefix = operation["prefix"]
|
22
|
+
ns = operation["ns"]
|
23
|
+
complete_fn = operation.fetch("complete-fn", "top-level")
|
24
|
+
|
25
|
+
if prefix.nil? || parse_string(prefix).nil?
|
26
|
+
response.set("completions", [])
|
27
|
+
else
|
28
|
+
ns_object = if ns.empty?
|
29
|
+
::Object
|
30
|
+
else
|
31
|
+
@workspace.lookup_module(ns)
|
32
|
+
end
|
33
|
+
|
34
|
+
# If the prefix isn't parseable, return an empty list
|
35
|
+
response.set("completions", lookup_module(prefix, klass: ns_object, completion_fn: complete_fn))
|
36
|
+
end
|
37
|
+
response.status("done")
|
38
|
+
response
|
39
|
+
end
|
40
|
+
|
41
|
+
def lookup_module(module_name, klass: ::Object, completion_fn: "top-level")
|
42
|
+
node = parse_string(module_name)
|
43
|
+
case node.type
|
44
|
+
when :const
|
45
|
+
ns = lookup_module_ast(node.children.first, klass)
|
46
|
+
prefix = node.children.last
|
47
|
+
all_constants(ns, prefix)
|
48
|
+
when :send
|
49
|
+
ns = lookup_module_ast(node.children.first, klass)
|
50
|
+
prefix = node.children.last
|
51
|
+
if completion_fn == "method"
|
52
|
+
all_constants(ns, prefix) + encode_methods(class_instance_methods(ns, prefix) + class_singleton_methods(::Kernel, prefix))
|
53
|
+
else
|
54
|
+
all_constants(ns, prefix) + encode_methods(class_methods(ns, prefix) + class_singleton_methods(::Kernel, prefix))
|
55
|
+
end
|
56
|
+
else
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_string(string)
|
62
|
+
buffer = Parser::Source::Buffer.new("(string)")
|
63
|
+
buffer.source = string
|
64
|
+
Parser::CurrentRuby.new.parse(buffer)
|
65
|
+
end
|
66
|
+
|
67
|
+
def lookup_module_ast(node, klass = ::Object)
|
68
|
+
return klass if node.nil?
|
69
|
+
|
70
|
+
case node.type
|
71
|
+
when :cbase
|
72
|
+
::Object
|
73
|
+
when :const
|
74
|
+
if node.children.first.nil?
|
75
|
+
klass.const_get(node.children.last)
|
76
|
+
else
|
77
|
+
lookup_module_ast(node.children.first, klass).const_get(node.children.last)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
raise ModuleLookupError, "Unknown node type #{node.type}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def parent_constant(ns_object)
|
85
|
+
ns_object_name = ns_object.to_s
|
86
|
+
parent_name, _ = ns_object_name.rpartition("::")
|
87
|
+
parent_name.empty? ? nil : ::Object.const_get(parent_name)
|
88
|
+
end
|
89
|
+
|
90
|
+
def all_constants(ns_object, prefix)
|
91
|
+
consts = []
|
92
|
+
ns_object.constants.grep(/^#{prefix}/).each do |constant|
|
93
|
+
consts << constant.to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
# Search up the tree to find all the other constants
|
97
|
+
constant = ns_object
|
98
|
+
loop do
|
99
|
+
constant = parent_constant(constant)
|
100
|
+
break if constant.nil?
|
101
|
+
|
102
|
+
constant.constants.grep(/^#{prefix}/).each do |constant|
|
103
|
+
consts << constant.to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
::Object.constants.grep(/^#{prefix}/).each do |constant|
|
108
|
+
consts << constant.to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
consts.map do |constant|
|
112
|
+
{
|
113
|
+
"candidate" => constant,
|
114
|
+
"type" => "constant"
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Get all instance methods that match a +prefix+ for a given object +obj+
|
121
|
+
#
|
122
|
+
# This method should be called when in the context of an
|
123
|
+
# instance method, as all other instance methods will be
|
124
|
+
# acessable.
|
125
|
+
def class_instance_methods(obj, prefix)
|
126
|
+
Set.new(obj.instance_methods.grep(/^#{prefix}/))
|
127
|
+
end
|
128
|
+
|
129
|
+
def class_methods(obj, prefix)
|
130
|
+
Set.new(obj.methods.grep(/^#{prefix}/))
|
131
|
+
end
|
132
|
+
|
133
|
+
def class_singleton_methods(obj, prefix)
|
134
|
+
Set.new(obj.singleton_methods.grep(/^#{prefix}/))
|
135
|
+
end
|
136
|
+
|
137
|
+
def encode_methods(methods)
|
138
|
+
methods.map do |method|
|
139
|
+
{
|
140
|
+
"candidate" => method.to_s,
|
141
|
+
"type" => "method"
|
142
|
+
}
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require "rider_server/operation"
|
2
|
+
require "rider_server/response"
|
3
|
+
require "rider_server/inspect"
|
4
|
+
|
5
|
+
module RiderServer
|
6
|
+
Operation.define do
|
7
|
+
name "lookup"
|
8
|
+
documentation "Get info about a symbol."
|
9
|
+
|
10
|
+
argument :id, :string, "The request id", required: true
|
11
|
+
argument :sym, :string, "The symbol to lookup", required: true
|
12
|
+
argument :lookup_fn, :string, "What lookup function to use, top-level, module, method or singleton-method"
|
13
|
+
argument :ns, :string, "The namespace to search for completions"
|
14
|
+
|
15
|
+
def handle(controller, operation)
|
16
|
+
response = Response.new(operation)
|
17
|
+
ns = operation["ns"]
|
18
|
+
sym = operation["sym"]
|
19
|
+
lookup_fn = operation.fetch("lookup-fn", "top-level")
|
20
|
+
|
21
|
+
if sym.nil? || parse_string(sym).nil?
|
22
|
+
response.set("info", {})
|
23
|
+
else
|
24
|
+
ns_object = if ns.empty?
|
25
|
+
::Object
|
26
|
+
else
|
27
|
+
workspace.lookup_module(ns)
|
28
|
+
end
|
29
|
+
|
30
|
+
# If the prefix isn't parseable, return an empty list
|
31
|
+
response.set("info", lookup_module(sym, klass: ns_object, lookup_fn: lookup_fn))
|
32
|
+
end
|
33
|
+
response.status("done")
|
34
|
+
response
|
35
|
+
end
|
36
|
+
|
37
|
+
def lookup_module(module_name, klass: ::Object, lookup_fn: "top-level")
|
38
|
+
node = parse_string(module_name)
|
39
|
+
case node.type
|
40
|
+
when :const
|
41
|
+
ns = lookup_module_ast(node.children.first, klass)
|
42
|
+
name node.children.last
|
43
|
+
encode_const(ns, name)
|
44
|
+
when :send
|
45
|
+
ns = lookup_module_ast(node.children.first, klass)
|
46
|
+
prefix = node.children.last
|
47
|
+
if lookup_fn == "method"
|
48
|
+
encode_method(ns.instance_method(prefix))
|
49
|
+
else
|
50
|
+
encode_method(ns.method(prefix))
|
51
|
+
end
|
52
|
+
else
|
53
|
+
[]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_string(string)
|
58
|
+
buffer = Parser::Source::Buffer.new("(string)")
|
59
|
+
buffer.source = string
|
60
|
+
Parser::CurrentRuby.new.parse(buffer)
|
61
|
+
end
|
62
|
+
|
63
|
+
def lookup_module_ast(node, klass = ::Object)
|
64
|
+
return klass if node.nil?
|
65
|
+
|
66
|
+
case node.type
|
67
|
+
when :cbase
|
68
|
+
::Object
|
69
|
+
when :const
|
70
|
+
if node.children.first.nil?
|
71
|
+
klass.const_get(node.children.last)
|
72
|
+
else
|
73
|
+
lookup_module_ast(node.children.first, klass).const_get(node.children.last)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
raise ModuleLookupError, "Unknown node type #{node.type}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def encode_const(ns, const_name)
|
81
|
+
if ns.const_defined? const_name
|
82
|
+
{
|
83
|
+
"name" => "#{ns}::#{const_name}",
|
84
|
+
"source_location" => ns.const_source_location(const_name)
|
85
|
+
}
|
86
|
+
else
|
87
|
+
{}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def encode_method(thing)
|
92
|
+
{
|
93
|
+
"name" => thing.name.to_s,
|
94
|
+
"source_location" => thing.source_location
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def workspace
|
99
|
+
@workspace ||= Workspace.new
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "rider_server/operation"
|
2
|
+
require "rider_server/response"
|
3
|
+
|
4
|
+
module RiderServer
|
5
|
+
Operation.define do
|
6
|
+
name "ls-sessions"
|
7
|
+
documentation "List all sessions"
|
8
|
+
|
9
|
+
argument :id, :string, "The request id", required: true
|
10
|
+
|
11
|
+
def handle(controller, operation)
|
12
|
+
response = Response.new(operation)
|
13
|
+
response.set("sessions", controller.sessions.map { |k, v| k })
|
14
|
+
response.set("rider/session-headings",
|
15
|
+
[
|
16
|
+
{
|
17
|
+
"id" => "id",
|
18
|
+
"name" => "ID",
|
19
|
+
"length" => 36
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"id" => "namespace_name",
|
23
|
+
"name" => "Namespace",
|
24
|
+
"length" => 25
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"id" => "history_items",
|
28
|
+
"name" => "History Items",
|
29
|
+
"length" => 5
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"id" => "exceptions",
|
33
|
+
"name" => "Exceptions",
|
34
|
+
"length" => 5
|
35
|
+
}
|
36
|
+
])
|
37
|
+
response.set("rider/sessions", controller.sessions.map { |k, v| session_summary(v) })
|
38
|
+
response.status("done")
|
39
|
+
response
|
40
|
+
end
|
41
|
+
|
42
|
+
def session_summary(session)
|
43
|
+
{
|
44
|
+
"id" => session.id,
|
45
|
+
"namespace_name" => session.workspace.namespace_name,
|
46
|
+
"history_items" => session.history.length.to_s,
|
47
|
+
"exceptions" => session.exceptions.length.to_s
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "rider_server/operation"
|
2
|
+
require "rider_server/response"
|
3
|
+
|
4
|
+
module RiderServer
|
5
|
+
Operation.define do
|
6
|
+
name "toggle-catch-all-exceptions"
|
7
|
+
documentation "Enable catching all exceptions. Not just the ones with a session."
|
8
|
+
|
9
|
+
argument :id, :string, "The request id", required: true
|
10
|
+
|
11
|
+
def handle(controller, operation)
|
12
|
+
value = if controller.toggle_capture_exceptions
|
13
|
+
"enabled"
|
14
|
+
else
|
15
|
+
"disabled"
|
16
|
+
end
|
17
|
+
|
18
|
+
response = Response.new(operation)
|
19
|
+
response.status("done")
|
20
|
+
response.set("value", value)
|
21
|
+
response
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -12,112 +12,78 @@ require "rider_server/session"
|
|
12
12
|
require "rider_server/errors"
|
13
13
|
require "rider_server/response"
|
14
14
|
require "rider_server/core_ext/array"
|
15
|
+
require "rider_server/core_ext/class"
|
16
|
+
require "rider_server/core_ext/env"
|
15
17
|
require "rider_server/core_ext/hash"
|
18
|
+
require "rider_server/core_ext/kernel"
|
19
|
+
require "rider_server/core_ext/module"
|
16
20
|
require "rider_server/core_ext/object"
|
17
21
|
require "rider_server/core_ext/string"
|
18
22
|
require "rider_server/core_ext/symbol"
|
19
|
-
require "rider_server/
|
20
|
-
require "rider_server/
|
21
|
-
require "rider_server/
|
22
|
-
require "rider_server/
|
23
|
-
require "rider_server/
|
24
|
-
require "rider_server/
|
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"
|
23
|
+
require "rider_server/operations/clone"
|
24
|
+
require "rider_server/operations/close"
|
25
|
+
require "rider_server/operations/completions"
|
26
|
+
require "rider_server/operations/lookup"
|
27
|
+
require "rider_server/operations/ls_sessions"
|
28
|
+
require "rider_server/operations/toggle_catch_all_exceptions"
|
35
29
|
|
36
30
|
module RiderServer
|
31
|
+
def self.create_operation_handler(config, response_queue)
|
32
|
+
Operations.new(config, response_queue)
|
33
|
+
end
|
34
|
+
|
37
35
|
class Operations
|
38
36
|
include RiderServer::Logger
|
39
37
|
|
40
|
-
attr_reader :executing_requests
|
41
38
|
attr_reader :sessions
|
42
|
-
attr_reader :stdin, :stdout, :stderr
|
43
39
|
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
40
|
|
65
|
-
def initialize(response_queue)
|
41
|
+
def initialize(config, response_queue)
|
42
|
+
@config = config
|
66
43
|
@sessions = {}
|
67
44
|
@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
45
|
end
|
74
46
|
|
75
47
|
def send_response(response)
|
76
48
|
if response
|
77
49
|
@response_queue.push(response)
|
78
|
-
if response.done?
|
79
|
-
@executing_requests.delete(response.id)
|
80
|
-
end
|
81
50
|
end
|
82
51
|
end
|
83
52
|
|
84
|
-
def handle(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
session
|
91
|
-
|
92
|
-
if @operations.key? op
|
93
|
-
@operations[op].validate_request!(operation)
|
94
|
-
send_response(@operations[op].handle(session, operation))
|
53
|
+
def handle(request)
|
54
|
+
op = request.op
|
55
|
+
log.info("Handling operation '#{request.inspect}'")
|
56
|
+
session = get_session(request.session)
|
57
|
+
if Operation.handles?(request)
|
58
|
+
send_response(Operation.handle(self, request))
|
59
|
+
elsif !session.nil? && SessionOperation.handles?(request)
|
60
|
+
send_response(SessionOperation.handle(session, request))
|
95
61
|
else
|
96
62
|
log.warn("Unknown operation '#{op}' requested")
|
97
|
-
response = Response.new(
|
63
|
+
response = Response.new(request)
|
98
64
|
response.status "unknown-op", "done"
|
99
65
|
send_response(response)
|
100
66
|
end
|
101
67
|
rescue ScriptError, StandardError => e
|
102
|
-
response = Response.new(
|
68
|
+
response = Response.new(request)
|
103
69
|
response.set("ex", e.inspect)
|
104
70
|
response.set("out", e.full_message)
|
105
71
|
response.status("eval-error", "done")
|
72
|
+
log.error "Error handling request: #{e}\n #{e.backtrace.join("\n")}"
|
106
73
|
if session
|
107
|
-
|
108
|
-
response.set("rider/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)
|
74
|
+
exception = session.add_exception(request.id, e)
|
75
|
+
response.set("rider/exception-id", exception["id"])
|
115
76
|
end
|
77
|
+
RiderServer::Services::CaptureExceptions.handle_exception(e)
|
116
78
|
send_response(response)
|
117
79
|
end
|
118
80
|
|
81
|
+
#
|
82
|
+
# Sessions
|
83
|
+
#
|
84
|
+
|
119
85
|
def new_session
|
120
|
-
|
86
|
+
RiderServer.create_session(@config, @response_queue)
|
121
87
|
end
|
122
88
|
|
123
89
|
def get_session(id)
|
@@ -132,5 +98,13 @@ module RiderServer
|
|
132
98
|
def delete_session(session_id)
|
133
99
|
@sessions.delete(session_id)
|
134
100
|
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Exceptions
|
104
|
+
#
|
105
|
+
|
106
|
+
def toggle_capture_exceptions
|
107
|
+
@config.capture_exceptions(!@config.capture_exceptions)
|
108
|
+
end
|
135
109
|
end
|
136
110
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# request.rb -- A simple wrapper around a request
|
5
|
+
#
|
6
|
+
# Author: Russell Sim
|
7
|
+
# Copyright (c) 2024 Russell Sim
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
|
10
|
+
require "bencode"
|
11
|
+
|
12
|
+
module RiderServer
|
13
|
+
class Request
|
14
|
+
def initialize(operation)
|
15
|
+
raise "Operation ID cannot be nil" if operation["id"].nil?
|
16
|
+
raise "Operation name cannot be nil" if operation["op"].nil?
|
17
|
+
|
18
|
+
@data = operation
|
19
|
+
end
|
20
|
+
|
21
|
+
def op
|
22
|
+
@data["op"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def id
|
26
|
+
@data["id"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def session
|
30
|
+
@data["session"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def set(key, value)
|
34
|
+
@data[key] = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def fetch(*args)
|
38
|
+
@data.fetch(*args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def key?(name)
|
42
|
+
@data.key? name
|
43
|
+
end
|
44
|
+
|
45
|
+
def [](name)
|
46
|
+
@data[name]
|
47
|
+
end
|
48
|
+
|
49
|
+
def []=(name, value)
|
50
|
+
@data[name] = value
|
51
|
+
end
|
52
|
+
|
53
|
+
def inspect
|
54
|
+
"#<RiderServer::Request:#{object_id} id=#{id} session=#{session} op=#{op}}>"
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_h
|
58
|
+
@data
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -42,8 +42,16 @@ module RiderServer
|
|
42
42
|
@data.fetch(*args)
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
46
|
-
@data
|
45
|
+
def key?(name)
|
46
|
+
@data.key? name
|
47
|
+
end
|
48
|
+
|
49
|
+
def [](name)
|
50
|
+
@data[name]
|
51
|
+
end
|
52
|
+
|
53
|
+
def []=(name, value)
|
54
|
+
@data[name] = value
|
47
55
|
end
|
48
56
|
|
49
57
|
def status(*value)
|