iruby 0.3 → 0.7.0
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 +5 -5
- data/.github/workflows/ubuntu.yml +62 -0
- data/CHANGES.md +203 -0
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/README.md +137 -87
- data/Rakefile +36 -10
- data/ci/Dockerfile.base.erb +41 -0
- data/ci/Dockerfile.main.erb +7 -0
- data/ci/requirements.txt +1 -0
- data/docker/setup.sh +15 -0
- data/docker/test.sh +7 -0
- data/iruby.gemspec +14 -18
- data/lib/iruby.rb +14 -8
- data/lib/iruby/backend.rb +38 -10
- data/lib/iruby/command.rb +67 -15
- data/lib/iruby/display.rb +77 -41
- data/lib/iruby/event_manager.rb +40 -0
- data/lib/iruby/formatter.rb +3 -3
- data/lib/iruby/input.rb +6 -6
- data/lib/iruby/input/README.md +299 -0
- data/lib/iruby/input/autoload.rb +1 -1
- data/lib/iruby/input/builder.rb +4 -4
- data/lib/iruby/input/button.rb +2 -2
- data/lib/iruby/input/cancel.rb +1 -1
- data/lib/iruby/input/checkbox.rb +3 -3
- data/lib/iruby/input/date.rb +3 -3
- data/lib/iruby/input/field.rb +2 -2
- data/lib/iruby/input/file.rb +3 -3
- data/lib/iruby/input/form.rb +6 -6
- data/lib/iruby/input/label.rb +4 -4
- data/lib/iruby/input/multiple.rb +10 -10
- data/lib/iruby/input/popup.rb +2 -2
- data/lib/iruby/input/radio.rb +6 -6
- data/lib/iruby/input/select.rb +8 -8
- data/lib/iruby/input/textarea.rb +1 -1
- data/lib/iruby/input/widget.rb +2 -2
- data/lib/iruby/jupyter.rb +77 -0
- data/lib/iruby/kernel.rb +204 -36
- data/lib/iruby/ostream.rb +29 -8
- data/lib/iruby/session.rb +117 -0
- data/lib/iruby/session/cztop.rb +4 -0
- data/lib/iruby/session_adapter.rb +72 -0
- data/lib/iruby/session_adapter/cztop_adapter.rb +45 -0
- data/lib/iruby/session_adapter/ffirzmq_adapter.rb +55 -0
- data/lib/iruby/session_adapter/pyzmq_adapter.rb +77 -0
- data/lib/iruby/session_adapter/test_adapter.rb +49 -0
- data/lib/iruby/utils.rb +13 -2
- data/lib/iruby/version.rb +1 -1
- data/run-test.sh +12 -0
- data/tasks/ci.rake +65 -0
- data/test/helper.rb +136 -0
- data/test/integration_test.rb +22 -11
- data/test/iruby/backend_test.rb +37 -0
- data/test/iruby/command_test.rb +207 -0
- data/test/iruby/event_manager_test.rb +92 -0
- data/test/iruby/jupyter_test.rb +27 -0
- data/test/iruby/kernel_test.rb +185 -0
- data/test/iruby/mime_test.rb +50 -0
- data/test/iruby/multi_logger_test.rb +1 -5
- data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
- data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
- data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
- data/test/iruby/session_adapter_test.rb +91 -0
- data/test/iruby/session_test.rb +48 -0
- data/test/run-test.rb +19 -0
- metadata +120 -50
- data/.travis.yml +0 -16
- data/CHANGES +0 -143
- data/CONTRIBUTORS +0 -19
- data/lib/iruby/session/rbczmq.rb +0 -68
- data/test/test_helper.rb +0 -5
data/lib/iruby/kernel.rb
CHANGED
@@ -1,36 +1,126 @@
|
|
1
1
|
module IRuby
|
2
|
+
ExecutionInfo = Struct.new(:raw_cell, :store_history, :silent)
|
3
|
+
|
2
4
|
class Kernel
|
3
5
|
RED = "\e[31m"
|
4
|
-
WHITE = "\e[37m"
|
5
6
|
RESET = "\e[0m"
|
6
7
|
|
7
|
-
|
8
|
+
@events = EventManager.new([:initialized])
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Return the event manager defined in the `IRuby::Kernel` class.
|
12
|
+
# This event manager can handle the following event:
|
13
|
+
#
|
14
|
+
# - `initialized`: The event occurred after the initialization of
|
15
|
+
# a `IRuby::Kernel` instance is finished
|
16
|
+
#
|
17
|
+
# @example Registering initialized event
|
18
|
+
# IRuby::Kernel.events.register(:initialized) do |result|
|
19
|
+
# STDERR.puts "IRuby kernel has been initialized"
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# @see IRuby::EventManager
|
23
|
+
# @see IRuby::Kernel#events
|
24
|
+
attr_reader :events
|
25
|
+
|
26
|
+
# Returns the singleton kernel instance
|
8
27
|
attr_accessor :instance
|
9
28
|
end
|
10
29
|
|
30
|
+
# Returns a session object
|
11
31
|
attr_reader :session
|
12
32
|
|
13
|
-
|
33
|
+
EVENTS = [
|
34
|
+
:pre_execute,
|
35
|
+
:pre_run_cell,
|
36
|
+
:post_run_cell,
|
37
|
+
:post_execute
|
38
|
+
].freeze
|
39
|
+
|
40
|
+
def initialize(config_file, session_adapter_name=nil)
|
14
41
|
@config = MultiJson.load(File.read(config_file))
|
15
42
|
IRuby.logger.debug("IRuby kernel start with config #{@config}")
|
16
43
|
Kernel.instance = self
|
17
44
|
|
18
|
-
@session = Session.new(@config)
|
45
|
+
@session = Session.new(@config, session_adapter_name)
|
19
46
|
$stdout = OStream.new(@session, :stdout)
|
20
47
|
$stderr = OStream.new(@session, :stderr)
|
21
48
|
|
49
|
+
init_parent_process_poller
|
50
|
+
|
51
|
+
@events = EventManager.new(EVENTS)
|
22
52
|
@execution_count = 0
|
23
|
-
@backend =
|
53
|
+
@backend = PlainBackend.new
|
24
54
|
@running = true
|
55
|
+
|
56
|
+
self.class.events.trigger(:initialized, self)
|
25
57
|
end
|
26
58
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
59
|
+
# Returns the event manager defined in a `IRuby::Kernel` instance.
|
60
|
+
# This event manager can handle the following events:
|
61
|
+
#
|
62
|
+
# - `pre_execute`: The event occurred before running the code
|
63
|
+
#
|
64
|
+
# - `pre_run_cell`: The event occurred before running the code and
|
65
|
+
# if the code execution is not silent
|
66
|
+
#
|
67
|
+
# - `post_execute`: The event occurred after running the code
|
68
|
+
#
|
69
|
+
# - `post_run_cell`: The event occurred after running the code and
|
70
|
+
# if the code execution is not silent
|
71
|
+
#
|
72
|
+
# The callback functions of `pre_run_cell` event must take one argument
|
73
|
+
# to get an `ExecutionInfo` object.
|
74
|
+
# The callback functions of `post_run_cell` event must take one argument
|
75
|
+
# to get the result of the code execution.
|
76
|
+
#
|
77
|
+
# @example Registering post_run_cell event
|
78
|
+
# IRuby::Kernel.instance.events.register(:post_run_cell) do |result|
|
79
|
+
# STDERR.puts "The result of the last execution: %p" % result
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# @see IRuby::EventManager
|
83
|
+
# @see IRuby::ExecutionInfo
|
84
|
+
# @see IRuby::Kernel.events
|
85
|
+
attr_reader :events
|
86
|
+
|
87
|
+
# Switch the backend (interactive shell) system
|
88
|
+
#
|
89
|
+
# @param backend [:irb,:plain,:pry] Specify the backend name switched to
|
90
|
+
#
|
91
|
+
# @return [true,false] true if the switching succeeds, otherwise false
|
92
|
+
def switch_backend!(backend)
|
93
|
+
name = case backend
|
94
|
+
when String, Symbol
|
95
|
+
name = backend.downcase
|
96
|
+
else
|
97
|
+
name = backend
|
98
|
+
end
|
99
|
+
|
100
|
+
backend_class = case name
|
101
|
+
when :irb, :plain
|
102
|
+
PlainBackend
|
103
|
+
when :pry
|
104
|
+
PryBackend
|
105
|
+
else
|
106
|
+
raise ArgumentError,
|
107
|
+
"Unknown backend name: %p" % backend
|
108
|
+
end
|
109
|
+
|
110
|
+
begin
|
111
|
+
new_backend = backend_class.new
|
112
|
+
@backend = new_backend
|
113
|
+
true
|
114
|
+
rescue Exception => e
|
115
|
+
unless LoadError === e
|
116
|
+
IRuby.logger.warn "Could not load #{backend_class}: " +
|
117
|
+
"#{e.message}\n#{e.backtrace.join("\n")}"
|
118
|
+
end
|
119
|
+
return false
|
120
|
+
end
|
32
121
|
end
|
33
122
|
|
123
|
+
# @private
|
34
124
|
def run
|
35
125
|
send_status :starting
|
36
126
|
while @running
|
@@ -38,8 +128,10 @@ module IRuby
|
|
38
128
|
end
|
39
129
|
end
|
40
130
|
|
131
|
+
# @private
|
41
132
|
def dispatch
|
42
133
|
msg = @session.recv(:reply)
|
134
|
+
IRuby.logger.debug "Kernel#dispatch: msg = #{msg}"
|
43
135
|
type = msg[:header]['msg_type']
|
44
136
|
raise "Unknown message type: #{msg.inspect}" unless type =~ /comm_|_request\Z/ && respond_to?(type)
|
45
137
|
begin
|
@@ -50,31 +142,54 @@ module IRuby
|
|
50
142
|
end
|
51
143
|
rescue Exception => e
|
52
144
|
IRuby.logger.debug "Kernel error: #{e.message}\n#{e.backtrace.join("\n")}"
|
53
|
-
@session.send(:publish, :error,
|
145
|
+
@session.send(:publish, :error, error_content(e))
|
54
146
|
end
|
55
147
|
|
148
|
+
# @private
|
56
149
|
def kernel_info_request(msg)
|
57
150
|
@session.send(:reply, :kernel_info_reply,
|
58
151
|
protocol_version: '5.0',
|
59
152
|
implementation: 'iruby',
|
60
|
-
banner: "IRuby #{IRuby::VERSION}",
|
61
153
|
implementation_version: IRuby::VERSION,
|
62
154
|
language_info: {
|
63
155
|
name: 'ruby',
|
64
156
|
version: RUBY_VERSION,
|
65
157
|
mimetype: 'application/x-ruby',
|
66
158
|
file_extension: '.rb'
|
67
|
-
}
|
159
|
+
},
|
160
|
+
banner: "IRuby #{IRuby::VERSION} (with #{@session.description})",
|
161
|
+
help_links: [
|
162
|
+
{
|
163
|
+
text: "Ruby Documentation",
|
164
|
+
url: "https://ruby-doc.org/"
|
165
|
+
}
|
166
|
+
],
|
167
|
+
status: :ok)
|
68
168
|
end
|
69
169
|
|
170
|
+
# @private
|
70
171
|
def send_status(status)
|
172
|
+
IRuby.logger.debug "Send status: #{status}"
|
71
173
|
@session.send(:publish, :status, execution_state: status)
|
72
174
|
end
|
73
175
|
|
176
|
+
# @private
|
74
177
|
def execute_request(msg)
|
75
178
|
code = msg[:content]['code']
|
76
|
-
|
77
|
-
|
179
|
+
store_history = msg[:content]['store_history']
|
180
|
+
silent = msg[:content]['silent']
|
181
|
+
|
182
|
+
@execution_count += 1 if store_history
|
183
|
+
|
184
|
+
unless silent
|
185
|
+
@session.send(:publish, :execute_input, code: code, execution_count: @execution_count)
|
186
|
+
end
|
187
|
+
|
188
|
+
events.trigger(:pre_execute)
|
189
|
+
unless silent
|
190
|
+
exec_info = ExecutionInfo.new(code, store_history, silent)
|
191
|
+
events.trigger(:pre_run_cell, exec_info)
|
192
|
+
end
|
78
193
|
|
79
194
|
content = {
|
80
195
|
status: :ok,
|
@@ -82,30 +197,49 @@ module IRuby
|
|
82
197
|
user_expressions: {},
|
83
198
|
execution_count: @execution_count
|
84
199
|
}
|
200
|
+
|
85
201
|
result = nil
|
86
202
|
begin
|
87
|
-
result = @backend.eval(code,
|
203
|
+
result = @backend.eval(code, store_history)
|
88
204
|
rescue SystemExit
|
89
205
|
content[:payload] << { source: :ask_exit }
|
90
206
|
rescue Exception => e
|
91
|
-
content =
|
207
|
+
content = error_content(e)
|
92
208
|
@session.send(:publish, :error, content)
|
209
|
+
content[:status] = :error
|
210
|
+
content[:execution_count] = @execution_count
|
211
|
+
end
|
212
|
+
|
213
|
+
unless result.nil? || silent
|
214
|
+
@session.send(:publish, :execute_result,
|
215
|
+
data: Display.display(result),
|
216
|
+
metadata: {},
|
217
|
+
execution_count: @execution_count)
|
93
218
|
end
|
219
|
+
|
220
|
+
events.trigger(:post_execute)
|
221
|
+
events.trigger(:post_run_cell, result) unless silent
|
222
|
+
|
94
223
|
@session.send(:reply, :execute_reply, content)
|
95
|
-
@session.send(:publish, :execute_result,
|
96
|
-
data: Display.display(result),
|
97
|
-
metadata: {},
|
98
|
-
execution_count: @execution_count) unless result.nil? || msg[:content]['silent']
|
99
224
|
end
|
100
225
|
|
101
|
-
|
102
|
-
|
103
|
-
|
226
|
+
# @private
|
227
|
+
def error_content(e)
|
228
|
+
rindex = e.backtrace.rindex{|line| line.start_with?(@backend.eval_path)} || -1
|
229
|
+
backtrace = SyntaxError === e && rindex == -1 ? [] : e.backtrace[0..rindex]
|
230
|
+
{ ename: e.class.to_s,
|
104
231
|
evalue: e.message,
|
105
|
-
traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *
|
106
|
-
|
232
|
+
traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *backtrace] }
|
233
|
+
end
|
234
|
+
|
235
|
+
# @private
|
236
|
+
def is_complete_request(msg)
|
237
|
+
# FIXME: the code completeness should be judged by using ripper or other Ruby parser
|
238
|
+
@session.send(:reply, :is_complete_reply,
|
239
|
+
status: :unknown)
|
107
240
|
end
|
108
241
|
|
242
|
+
# @private
|
109
243
|
def complete_request(msg)
|
110
244
|
# HACK for #26, only complete last line
|
111
245
|
code = msg[:content]['code']
|
@@ -115,51 +249,85 @@ module IRuby
|
|
115
249
|
end
|
116
250
|
@session.send(:reply, :complete_reply,
|
117
251
|
matches: @backend.complete(code),
|
118
|
-
status: :ok,
|
119
252
|
cursor_start: start.to_i,
|
120
|
-
cursor_end: msg[:content]['cursor_pos']
|
253
|
+
cursor_end: msg[:content]['cursor_pos'],
|
254
|
+
metadata: {},
|
255
|
+
status: :ok)
|
121
256
|
end
|
122
257
|
|
258
|
+
# @private
|
123
259
|
def connect_request(msg)
|
124
260
|
@session.send(:reply, :connect_reply, Hash[%w(shell_port iopub_port stdin_port hb_port).map {|k| [k, @config[k]] }])
|
125
261
|
end
|
126
262
|
|
263
|
+
# @private
|
127
264
|
def shutdown_request(msg)
|
128
265
|
@session.send(:reply, :shutdown_reply, msg[:content])
|
129
266
|
@running = false
|
130
267
|
end
|
131
268
|
|
269
|
+
# @private
|
132
270
|
def history_request(msg)
|
133
271
|
# we will just send back empty history for now, pending clarification
|
134
272
|
# as requested in ipython/ipython#3806
|
135
273
|
@session.send(:reply, :history_reply, history: [])
|
136
274
|
end
|
137
275
|
|
276
|
+
# @private
|
138
277
|
def inspect_request(msg)
|
139
|
-
|
140
|
-
@session.send(:reply, :inspect_reply,
|
141
|
-
status: :ok,
|
142
|
-
data: Display.display(result),
|
143
|
-
metadata: {})
|
144
|
-
rescue Exception => e
|
145
|
-
IRuby.logger.warn "Inspection error: #{e.message}\n#{e.backtrace.join("\n")}"
|
146
|
-
@session.send(:reply, :inspect_reply, status: :error)
|
278
|
+
# not yet implemented. See (#119).
|
279
|
+
@session.send(:reply, :inspect_reply, status: :ok, found: false, data: {}, metadata: {})
|
147
280
|
end
|
148
281
|
|
282
|
+
# @private
|
149
283
|
def comm_open(msg)
|
150
284
|
comm_id = msg[:content]['comm_id']
|
151
285
|
target_name = msg[:content]['target_name']
|
152
286
|
Comm.comm[comm_id] = Comm.target[target_name].new(target_name, comm_id)
|
153
287
|
end
|
154
288
|
|
289
|
+
# @private
|
155
290
|
def comm_msg(msg)
|
156
291
|
Comm.comm[msg[:content]['comm_id']].handle_msg(msg[:content]['data'])
|
157
292
|
end
|
158
293
|
|
294
|
+
# @private
|
159
295
|
def comm_close(msg)
|
160
296
|
comm_id = msg[:content]['comm_id']
|
161
297
|
Comm.comm[comm_id].handle_close(msg[:content]['data'])
|
162
298
|
Comm.comm.delete(comm_id)
|
163
299
|
end
|
300
|
+
|
301
|
+
private
|
302
|
+
|
303
|
+
def init_parent_process_poller
|
304
|
+
pid = ENV.fetch('JPY_PARENT_PID', 0).to_i
|
305
|
+
return unless pid > 1
|
306
|
+
|
307
|
+
case RUBY_PLATFORM
|
308
|
+
when /mswin/, /mingw/
|
309
|
+
# TODO
|
310
|
+
else
|
311
|
+
@parent_poller = start_parent_process_pollar_unix
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def start_parent_process_pollar_unix
|
316
|
+
Thread.start do
|
317
|
+
IRuby.logger.warn("parent process poller thread started.")
|
318
|
+
loop do
|
319
|
+
begin
|
320
|
+
current_ppid = Process.ppid
|
321
|
+
if current_ppid == 1
|
322
|
+
IRuby.logger.warn("parent process appears to exited, shutting down.")
|
323
|
+
exit!(1)
|
324
|
+
end
|
325
|
+
sleep 1
|
326
|
+
rescue Errno::EINTR
|
327
|
+
# ignored
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
164
332
|
end
|
165
333
|
end
|
data/lib/iruby/ostream.rb
CHANGED
@@ -25,22 +25,43 @@ module IRuby
|
|
25
25
|
alias_method :next, :read
|
26
26
|
alias_method :readline, :read
|
27
27
|
|
28
|
-
def write(
|
29
|
-
|
30
|
-
|
31
|
-
nil
|
28
|
+
def write(*obj)
|
29
|
+
str = build_string { |sio| sio.write(*obj) }
|
30
|
+
session_send(str)
|
32
31
|
end
|
33
32
|
alias_method :<<, :write
|
34
33
|
alias_method :print, :write
|
35
34
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
def printf(format, *obj)
|
36
|
+
str = build_string { |sio| sio.printf(format, *obj) }
|
37
|
+
session_send(str)
|
38
|
+
end
|
39
|
+
|
40
|
+
def puts(*obj)
|
41
|
+
str = build_string { |sio| sio.puts(*obj) }
|
42
|
+
session_send(str)
|
40
43
|
end
|
41
44
|
|
42
45
|
def writelines(lines)
|
43
46
|
lines.each { |s| write(s) }
|
44
47
|
end
|
48
|
+
|
49
|
+
# Called by irb
|
50
|
+
def set_encoding(extern, intern)
|
51
|
+
a = extern
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def build_string
|
57
|
+
StringIO.open { |sio| yield(sio); sio.string }
|
58
|
+
end
|
59
|
+
|
60
|
+
def session_send(str)
|
61
|
+
raise 'I/O operation on closed file' unless @session
|
62
|
+
|
63
|
+
@session.send(:publish, :stream, name: @name, text: str)
|
64
|
+
nil
|
65
|
+
end
|
45
66
|
end
|
46
67
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'iruby/session_adapter'
|
2
|
+
require 'iruby/session/mixin'
|
3
|
+
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
module IRuby
|
7
|
+
class Session
|
8
|
+
include SessionSerialize
|
9
|
+
|
10
|
+
def initialize(config, adapter_name=nil)
|
11
|
+
@config = config
|
12
|
+
@adapter = create_session_adapter(config, adapter_name)
|
13
|
+
@last_recvd_msg = nil
|
14
|
+
|
15
|
+
setup
|
16
|
+
setup_sockets
|
17
|
+
setup_heartbeat
|
18
|
+
setup_security
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :adapter, :config
|
22
|
+
|
23
|
+
def description
|
24
|
+
"#{@adapter.name} session adapter"
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_sockets
|
31
|
+
protocol, host = config.values_at('transport', 'ip')
|
32
|
+
shell_port = config['shell_port']
|
33
|
+
iopub_port = config['iopub_port']
|
34
|
+
stdin_port = config['stdin_port']
|
35
|
+
|
36
|
+
@shell_socket, @shell_port = @adapter.make_router_socket(protocol, host, shell_port)
|
37
|
+
@iopub_socket, @iopub_port = @adapter.make_pub_socket(protocol, host, iopub_port)
|
38
|
+
@stdin_socket, @stdin_port = @adapter.make_router_socket(protocol, host, stdin_port)
|
39
|
+
|
40
|
+
@sockets = {
|
41
|
+
publish: @iopub_socket,
|
42
|
+
reply: @shell_socket,
|
43
|
+
stdin: @stdin_socket
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def setup_heartbeat
|
48
|
+
protocol, host = config.values_at('transport', 'ip')
|
49
|
+
hb_port = config['hb_port']
|
50
|
+
@hb_socket, @hb_port = @adapter.make_rep_socket(protocol, host, hb_port)
|
51
|
+
@heartbeat_thread = Thread.start do
|
52
|
+
begin
|
53
|
+
# NOTE: this loop is copied from CZTop's old session code
|
54
|
+
@adapter.heartbeat_loop(@hb_socket)
|
55
|
+
rescue Exception => e
|
56
|
+
IRuby.logger.fatal "Kernel heartbeat died: #{e.message}\n#{e.backtrace.join("\n")}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def setup_security
|
62
|
+
@session_id = SecureRandom.uuid
|
63
|
+
unless config['key'].empty? || config['signature_scheme'].empty?
|
64
|
+
unless config['signature_scheme'] =~ /\Ahmac-/
|
65
|
+
raise "Unknown signature_scheme: #{config['signature_scheme']}"
|
66
|
+
end
|
67
|
+
digest_algorithm = config['signature_scheme'][/\Ahmac-(.*)\Z/, 1]
|
68
|
+
@hmac = OpenSSL::HMAC.new(config['key'], OpenSSL::Digest.new(digest_algorithm))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def send(socket_type, message_type, content)
|
73
|
+
sock = check_socket_type(socket_type)
|
74
|
+
idents = if socket_type == :reply && @last_recvd_msg
|
75
|
+
@last_recvd_msg[:idents]
|
76
|
+
else
|
77
|
+
message_type == :stream ? "stream.#{content[:name]}" : message_type
|
78
|
+
end
|
79
|
+
header = {
|
80
|
+
msg_type: message_type,
|
81
|
+
msg_id: SecureRandom.uuid,
|
82
|
+
username: 'kernel',
|
83
|
+
session: @session_id,
|
84
|
+
version: '5.0'
|
85
|
+
}
|
86
|
+
@adapter.send(sock, serialize(idents, header, content))
|
87
|
+
end
|
88
|
+
|
89
|
+
def recv(socket_type)
|
90
|
+
sock = check_socket_type(socket_type)
|
91
|
+
data = @adapter.recv(sock)
|
92
|
+
@last_recvd_msg = unserialize(data)
|
93
|
+
end
|
94
|
+
|
95
|
+
def recv_input
|
96
|
+
sock = check_socket_type(:stdin)
|
97
|
+
data = @adapter.recv(sock)
|
98
|
+
unserialize(data)[:content]["value"]
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def check_socket_type(socket_type)
|
104
|
+
case socket_type
|
105
|
+
when :publish, :reply, :stdin
|
106
|
+
@sockets[socket_type]
|
107
|
+
else
|
108
|
+
raise ArgumentError, "Invalid socket type #{socket_type}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def create_session_adapter(config, adapter_name)
|
113
|
+
adapter_class = SessionAdapter.select_adapter_class(adapter_name)
|
114
|
+
adapter_class.new(config)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|