rider-server 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.build.yml +3 -3
  3. data/CHANGELOG.md +17 -1
  4. data/README.rdoc +39 -0
  5. data/Rakefile +5 -0
  6. data/exe/rider-server +3 -3
  7. data/lib/rider_server/config.rb +76 -0
  8. data/lib/rider_server/core_ext/array.rb +3 -1
  9. data/lib/rider_server/core_ext/class.rb +5 -0
  10. data/lib/rider_server/core_ext/env.rb +14 -0
  11. data/lib/rider_server/core_ext/hash.rb +3 -1
  12. data/lib/rider_server/core_ext/kernel.rb +5 -0
  13. data/lib/rider_server/core_ext/module.rb +18 -0
  14. data/lib/rider_server/core_ext/object.rb +7 -1
  15. data/lib/rider_server/core_ext/string.rb +3 -1
  16. data/lib/rider_server/core_ext/symbol.rb +3 -1
  17. data/lib/rider_server/exception_extension.rb +2 -0
  18. data/lib/rider_server/inspect.rb +108 -32
  19. data/lib/rider_server/logger.rb +11 -4
  20. data/lib/rider_server/operation.rb +39 -20
  21. data/lib/rider_server/{ops → operations}/clone.rb +3 -2
  22. data/lib/rider_server/{ops → operations}/close.rb +3 -2
  23. data/lib/rider_server/operations/completions.rb +146 -0
  24. data/lib/rider_server/operations/lookup.rb +102 -0
  25. data/lib/rider_server/operations/ls_sessions.rb +51 -0
  26. data/lib/rider_server/operations/toggle_catch_all_exceptions.rb +24 -0
  27. data/lib/rider_server/operations.rb +42 -68
  28. data/lib/rider_server/request.rb +61 -0
  29. data/lib/rider_server/response.rb +10 -2
  30. data/lib/rider_server/server.rb +28 -16
  31. data/lib/rider_server/services/capture_exceptions.rb +1 -1
  32. data/lib/rider_server/services/rails.rb +1 -1
  33. data/lib/rider_server/session.rb +75 -44
  34. data/lib/rider_server/session_operation.rb +17 -0
  35. data/lib/rider_server/session_operations/eval.rb +61 -0
  36. data/lib/rider_server/session_operations/inspect.rb +123 -0
  37. data/lib/rider_server/session_operations/inspect_exception.rb +46 -0
  38. data/lib/rider_server/session_operations/interrupt.rb +29 -0
  39. data/lib/rider_server/session_operations/load_path.rb +19 -0
  40. data/lib/rider_server/session_operations/ls_exceptions.rb +28 -0
  41. data/lib/rider_server/session_operations/ls_services.rb +18 -0
  42. data/lib/rider_server/session_operations/service.rb +42 -0
  43. data/lib/rider_server/session_operations/set_namespace.rb +82 -0
  44. data/lib/rider_server/session_operations/set_namespace_variable.rb +81 -0
  45. data/lib/rider_server/session_operations/stdin.rb +19 -0
  46. data/lib/rider_server/utils.rb +7 -7
  47. data/lib/rider_server/validate/array.rb +32 -0
  48. data/lib/rider_server/validate/base.rb +28 -0
  49. data/lib/rider_server/validate/boolean.rb +47 -0
  50. data/lib/rider_server/validate/hash.rb +32 -0
  51. data/lib/rider_server/validate/integer.rb +56 -0
  52. data/lib/rider_server/validate/predicates.rb +30 -0
  53. data/lib/rider_server/validate/string.rb +60 -0
  54. data/lib/rider_server/validate/symbol.rb +90 -0
  55. data/lib/rider_server/validate.rb +15 -0
  56. data/lib/rider_server/version.rb +1 -1
  57. data/lib/rider_server/workspace.rb +1 -1
  58. data/lib/rider_server.rb +3 -1
  59. metadata +54 -24
  60. data/README.md +0 -46
  61. data/lib/rider_server/ops/completions.rb +0 -145
  62. data/lib/rider_server/ops/eval.rb +0 -62
  63. data/lib/rider_server/ops/inspect.rb +0 -121
  64. data/lib/rider_server/ops/inspect_exception.rb +0 -47
  65. data/lib/rider_server/ops/interrupt.rb +0 -30
  66. data/lib/rider_server/ops/load_path.rb +0 -20
  67. data/lib/rider_server/ops/lookup.rb +0 -104
  68. data/lib/rider_server/ops/ls_exceptions.rb +0 -29
  69. data/lib/rider_server/ops/ls_services.rb +0 -19
  70. data/lib/rider_server/ops/ls_sessions.rb +0 -52
  71. data/lib/rider_server/ops/service.rb +0 -43
  72. data/lib/rider_server/ops/set_namespace.rb +0 -79
  73. data/lib/rider_server/ops/set_namespace_variable.rb +0 -80
  74. data/lib/rider_server/ops/stdin.rb +0 -20
  75. data/lib/rider_server/ops/toggle_catch_all_exceptions.rb +0 -27
@@ -51,7 +51,7 @@ module RiderServer
51
51
  end
52
52
  end
53
53
  rescue => e
54
- @session.push_exception(stream_id, e)
54
+ @session.add_exception(stream_id, e)
55
55
  nputs "Error starting Rails Server: #{e.message}"
56
56
  end
57
57
  end
@@ -15,8 +15,28 @@ require "rider_server/services/rails"
15
15
  require "rider_server/services/capture_io"
16
16
  require "rider_server/services/capture_exceptions"
17
17
  require "rider_server/logger"
18
+ require "rider_server/session_operations/eval"
19
+ require "rider_server/session_operations/inspect"
20
+ require "rider_server/session_operations/inspect_exception"
21
+ require "rider_server/session_operations/interrupt"
22
+ require "rider_server/session_operations/load_path"
23
+ require "rider_server/session_operations/ls_exceptions"
24
+ require "rider_server/session_operations/ls_services"
25
+ require "rider_server/session_operations/service"
26
+ require "rider_server/session_operations/set_namespace"
27
+ require "rider_server/session_operations/set_namespace_variable"
18
28
 
19
29
  module RiderServer
30
+ def self.create_session(config, response_queue, history: [])
31
+ session = Session.new(config, response_queue, history: history)
32
+
33
+ ObjectSpace.each_object(Class).select { |klass| klass < ::RiderServer::Service }.map do |klass, h|
34
+ session.add_service klass
35
+ end
36
+
37
+ session
38
+ end
39
+
20
40
  class Session
21
41
  include RiderServer::Logger
22
42
 
@@ -27,24 +47,17 @@ module RiderServer
27
47
  attr_reader :response_queue
28
48
  attr_reader :history
29
49
 
30
- SERVICES = [
31
- Services::Rails,
32
- Services::CaptureIO,
33
- Services::CaptureExceptions
34
- ]
35
-
36
- def initialize(response_queue, history: [])
50
+ def initialize(config, response_queue, history: [])
37
51
  @id = SecureRandom.uuid
52
+ @config = config
38
53
  @history = history
39
54
  @workspace = Workspace.new
40
55
  @queue = Thread::Queue.new
41
- @exceptions = Utils::FixedArray.new
56
+ @exceptions = Utils::FixedArray.new(max_size: config.exception_history_size)
42
57
  @response_queue = response_queue
43
58
  @exception_queue = Thread::Queue.new
44
59
  @evaluations = {}
45
- @services = SERVICES.each_with_object({}) do |klass, h|
46
- h[klass.service_name] = klass.new(self)
47
- end
60
+ @services = {}
48
61
 
49
62
  # XXX Side effects in initializer, :()
50
63
  start_exception_processing
@@ -56,34 +69,40 @@ module RiderServer
56
69
  end
57
70
  end
58
71
 
72
+ def stdin
73
+ ::STDIN # rubocop:disable Style/GlobalStdStream
74
+ end
75
+
59
76
  def clone
60
- Session.new(@responses_queue, history: @history.clone)
77
+ RiderServer.create_session(@responses_queue, history: @history.clone)
61
78
  end
62
79
 
63
80
  #
64
81
  # Input History
65
82
  #
66
83
 
84
+ # Push an event onto the history stack.
67
85
  def push_history(event)
68
86
  @history.push(event)
69
87
  end
70
88
 
71
- def last_history
72
- @history.last
73
- end
74
-
75
89
  #
76
90
  # Historical Results
77
91
  #
78
92
 
93
+ # Return a Hash containing all historical evaluations.
79
94
  def result_history
80
95
  @result_history ||= {}
81
96
  end
82
97
 
98
+ # Add an execution result to the history. The +evaluation_id+ is
99
+ # the operation id of the evaluation and the +value+ is the result
100
+ # of the evaluation.
83
101
  def add_result(evaluation_id, value)
84
102
  result_history[evaluation_id] = value
85
103
  end
86
104
 
105
+ # Return a historical result of an evaluation by +evaluation_id+.
87
106
  def get_result(evaluation_id)
88
107
  raise "Missing history item #{evaluation_id}." unless result_history.key?(evaluation_id)
89
108
  result_history[evaluation_id]
@@ -93,41 +112,33 @@ module RiderServer
93
112
  # Historical Exceptions
94
113
  #
95
114
 
96
- def wrap_exception(operation_id, exception, metadata = {})
97
- id = SecureRandom.uuid
98
- {
99
- "id" => id,
100
- "operation_id" => operation_id,
101
- "created_at" => DateTime.now,
102
- "exception" => exception,
103
- "metadata" => metadata
104
- }
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.
119
+ def add_exception(operation_id, exception, metadata = {})
120
+ ex = wrap_exception(operation_id, exception, metadata)
121
+ @exception_queue.push(ex)
122
+ ex
105
123
  end
106
124
 
107
- def add_exception(operation_id, exception, metadata = {})
108
- id = SecureRandom.uuid
109
- @exceptions << wrap_exception(operation_id, exception, metadata)
110
- id
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
111
131
  end
112
132
 
133
+ # Return an exception by +exception_id+. Raises an exception if
134
+ # the exception doesn't exist.
113
135
  def get_exception(exception_id)
114
136
  exception = @exceptions.find { |item| item["id"] == exception_id }
115
137
  raise "Missing exception #{exception_id}." unless exception
116
138
  exception
117
139
  end
118
140
 
119
- # A threadsafe way to add exceptions
120
- def push_exception(operation_id, exception, metadata = {})
121
- ex = wrap_exception(operation_id, exception, metadata)
122
- @exception_queue.push(ex)
123
- ex
124
- end
125
-
126
- def push_anonymous_exception(exception)
127
- @exception_queue.push(exception)
128
- exception
129
- end
130
-
141
+ # Start a thread to process exceptions from the exception queue.
131
142
  def start_exception_processing
132
143
  return if @exception_processing_thread
133
144
 
@@ -138,6 +149,7 @@ module RiderServer
138
149
  end
139
150
  end
140
151
 
152
+ # Stop the exception processing thread.
141
153
  def stop_exception_processing
142
154
  @exception_processing_thread.exit
143
155
  @exception_processing_thread = nil
@@ -168,11 +180,17 @@ module RiderServer
168
180
  #
169
181
  # Service control
170
182
  #
183
+
184
+ def add_service(service_class)
185
+ cls = service_class.new(self)
186
+ @services[service_class.service_name] = cls
187
+ end
188
+
171
189
  def list_services
172
- SERVICES.map do |klass|
190
+ @services.map do |name, _|
173
191
  {
174
- "name" => klass.service_name,
175
- "state" => service_state(klass.service_name).to_s
192
+ "name" => name,
193
+ "state" => service_state(name).to_s
176
194
  }
177
195
  end
178
196
  end
@@ -198,5 +216,18 @@ module RiderServer
198
216
  :stopped
199
217
  end
200
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
201
232
  end
202
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
@@ -0,0 +1,42 @@
1
+ require "rider_server/operation"
2
+ require "rider_server/response"
3
+
4
+ module RiderServer
5
+ SessionOperation.define do
6
+ name "service"
7
+ documentation "Control a Ruby service integration"
8
+
9
+ argument :id, :string, "The request id", required: true
10
+ argument :service, :string, "The name of the Ruby service to control", required: true
11
+ argument :state, :string, "The desired state of the service", required: true
12
+
13
+ def handle(session, operation)
14
+ response = Response.new(operation)
15
+
16
+ service = operation["service"]
17
+ state = operation["state"]
18
+
19
+ current_state = session.service_state(service)
20
+
21
+ case state
22
+ when "start"
23
+ raise "Service already running" if current_state == "running"
24
+ session.start_service(service, response.id)
25
+ response.set("rider/stream", "true")
26
+ when "stop"
27
+ raise "Can't stop service #{service}. It's not running." if current_state == "stopped"
28
+ session.stop_service(service)
29
+ response.status("done")
30
+ else
31
+ # TODO: throwing this exception will caues a "done" response
32
+ # to be sent, which will implicitly close the stream. It
33
+ # might make sense to handle this more gracefully here.
34
+ raise "Unknown state #{state}"
35
+ end
36
+
37
+ response.set("service", service)
38
+ response.set("state", session.service_state(service).to_s)
39
+ response
40
+ end
41
+ end
42
+ end