rapel 0.1.0 → 0.2.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 +4 -4
- data/.gitignore +3 -0
- data/README.md +2 -5
- data/bin/console +3 -2
- data/bin/runtime.rb +65 -0
- data/lib/rapel.rb +83 -1
- data/lib/rapel/expression.rb +30 -0
- data/lib/rapel/replserver.rb +72 -0
- data/lib/rapel/runtime.rb +42 -0
- data/lib/rapel/version.rb +1 -1
- data/rapel.gemspec +1 -1
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b92563a1ed6631d218e18f28bdae877f2fc9d871
|
4
|
+
data.tar.gz: a6a5260a12414bf9741af4119225c2aa6670d881
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b67829358e692e0d1d10869537aca3b8292cd73733e7721464067c4c744198be3ea4d50b62b5345767b8e00c6a84bf547e2f1d338674752b469ad99f7629186
|
7
|
+
data.tar.gz: 4d27177c6ded616ace9ac0e74a2f06ad7d27f4d5374d48eb6b168332ee85190a2cd7a92625400cd41e17ca7f7fdf9cc0c8b19633aa1b892a12be55608f3c0b76
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# Rapel
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
Rapel (ruh-PELL) provides a multi-client, multi-runtime REPL server which accepts incoming expressions, e.g. 2+2, evaluates them in a runtime, and returns the result, e.g. 4.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -32,8 +30,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
30
|
|
33
31
|
## Contributing
|
34
32
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
36
|
-
|
33
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/domgetter/rapel.
|
37
34
|
|
38
35
|
## License
|
39
36
|
|
data/bin/console
CHANGED
data/bin/runtime.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
logger = File.open("#{File.dirname(__FILE__)}/runtime.log", "a")
|
5
|
+
logger.puts("my pid is #{$$}")
|
6
|
+
logger.flush
|
7
|
+
args = ARGV.select {|arg| arg.start_with? "--" }.map {|arg| arg[2..-1].split "="}.to_h
|
8
|
+
logger.puts("Starting runtime at port #{args["port"]}")
|
9
|
+
logger.flush
|
10
|
+
begin
|
11
|
+
server = TCPServer.new(args["port"])
|
12
|
+
rescue
|
13
|
+
logger.puts $!.inspect
|
14
|
+
logger.flush
|
15
|
+
end
|
16
|
+
begin
|
17
|
+
socket = TCPSocket.new('localhost', args["callback-port"])
|
18
|
+
socket.puts({pid: $$, session_id: args["uuid"]}.to_json)
|
19
|
+
rescue
|
20
|
+
logger.puts $!.inspect
|
21
|
+
logger.flush
|
22
|
+
end
|
23
|
+
|
24
|
+
def escape_newlines(string)
|
25
|
+
string.gsub("\\", "\\\\").gsub("\n", " \\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def unescape_newlines(string)
|
29
|
+
string.gsub(" \\n", "\n").gsub("\\\\", "\\")
|
30
|
+
end
|
31
|
+
|
32
|
+
loop do
|
33
|
+
begin
|
34
|
+
Thread.new(server.accept) do |client|
|
35
|
+
logger.puts("incoming connection from #{client.inspect}")
|
36
|
+
b389483479436 = binding
|
37
|
+
loop {
|
38
|
+
message = client.gets
|
39
|
+
logger.puts("processing message #{message.inspect} from #{client.inspect}")
|
40
|
+
if message.match(/shutdown#{args["port"]}/)
|
41
|
+
logger.puts("shutting down runtime on port #{args["port"]}")
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
begin
|
45
|
+
code = unescape_newlines(message)
|
46
|
+
value = eval(code, b389483479436)
|
47
|
+
rescue Exception => e
|
48
|
+
value = $!
|
49
|
+
end
|
50
|
+
begin
|
51
|
+
logger.puts("returning #{value.inspect} to #{client.inspect}")
|
52
|
+
logger.flush
|
53
|
+
client.puts(escape_newlines(value.inspect))
|
54
|
+
rescue Exception => e
|
55
|
+
logger.puts e.inspect
|
56
|
+
client.puts("")
|
57
|
+
end
|
58
|
+
}
|
59
|
+
client.close
|
60
|
+
end
|
61
|
+
rescue
|
62
|
+
break
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
data/lib/rapel.rb
CHANGED
@@ -1,5 +1,87 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'socket'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
Signal.trap("INT") do
|
6
|
+
Rapel.shutdown
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
|
10
|
+
class Hash
|
11
|
+
def slice(*keys)
|
12
|
+
keys.reduce({}) {|h, k| h[k] = self[k]}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TCPSocket
|
17
|
+
|
18
|
+
def accept_loop
|
19
|
+
loop do
|
20
|
+
message = JSON.parse(self.gets.chomp, symbolize_names: true)
|
21
|
+
$stdout.puts("Message received: #{message} from: #{self}")
|
22
|
+
case message[:op]
|
23
|
+
when "eval"
|
24
|
+
$stdout.puts("Eval message recieved: #{message[:code].inspect}")
|
25
|
+
begin
|
26
|
+
Rapel::REPLServer::Input.new("qer")
|
27
|
+
rescue
|
28
|
+
puts $!
|
29
|
+
end
|
30
|
+
yield Rapel::REPLServer::Input.new(message)
|
31
|
+
else
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
close
|
36
|
+
end
|
37
|
+
|
38
|
+
def repl
|
39
|
+
accept_loop do |input|
|
40
|
+
input.read do |expression, context|
|
41
|
+
expression.evaluate(context) do |result|
|
42
|
+
respond_with(result)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def respond_with(result)
|
49
|
+
response = result.to_json
|
50
|
+
self.puts response
|
51
|
+
$stdout.puts "returned #{response} to #{self}"
|
52
|
+
rescue Exception => e
|
53
|
+
$stdout.puts e.inspect
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
1
57
|
require "rapel/version"
|
58
|
+
require "rapel/replserver"
|
59
|
+
require "rapel/expression"
|
60
|
+
require "rapel/runtime"
|
2
61
|
|
3
62
|
module Rapel
|
4
|
-
|
63
|
+
def self.runtimes
|
64
|
+
@@server.runtimes
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.escape_newlines(string)
|
68
|
+
string.gsub("\\", "\\\\").gsub("\n", " \\n")
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.unescape_newlines(string)
|
72
|
+
string.gsub(" \\n", "\n").gsub("\\\\", "\\")
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.shutdown_runtimes
|
76
|
+
@@server.shutdown
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.start
|
80
|
+
@@server = REPLServer.new
|
81
|
+
@@server.start
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.shutdown
|
85
|
+
@@server.shutdown
|
86
|
+
end
|
5
87
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Rapel
|
2
|
+
|
3
|
+
class Expression
|
4
|
+
def initialize(exp)
|
5
|
+
@expression = exp
|
6
|
+
end
|
7
|
+
|
8
|
+
def evaluate(context)
|
9
|
+
$stdout.puts("Evaluating #{self.inspect} within #{context.inspect}")
|
10
|
+
result = {session_id: context.session_id}
|
11
|
+
begin
|
12
|
+
context.socket.puts(Rapel.escape_newlines(@expression))
|
13
|
+
value = context.socket.gets.chomp
|
14
|
+
result[:result] = Rapel.unescape_newlines(value)
|
15
|
+
rescue Exception => e
|
16
|
+
$stdout.puts e
|
17
|
+
result[:result] = ""
|
18
|
+
result[:error] = e.message
|
19
|
+
end
|
20
|
+
$stdout.puts "Received #{value.inspect} from #{context.inspect}"
|
21
|
+
|
22
|
+
yield result
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
@expression.inspect
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Rapel
|
2
|
+
|
3
|
+
class REPLServer
|
4
|
+
|
5
|
+
attr_reader :runtimes
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@runtimes = {}
|
9
|
+
server_port = 8091
|
10
|
+
$stdout.puts "Starting Rapel server on port #{server_port}"
|
11
|
+
@server = TCPServer.new(server_port)
|
12
|
+
callback_server_port = 8092
|
13
|
+
callback_server = TCPServer.new(callback_server_port)
|
14
|
+
|
15
|
+
session_id = SecureRandom.uuid
|
16
|
+
runtime = Runtime.new(callback_server_port, session_id)
|
17
|
+
@runtimes[session_id] = runtime
|
18
|
+
|
19
|
+
async_listen_for_runtimes(callback_server)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def async_new_repl_connections
|
24
|
+
Thread.new(@server.accept) do |conn|
|
25
|
+
$stdout.puts("Client connected on port: #{conn.addr[1]}")
|
26
|
+
conn.repl
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def async_listen_for_runtimes(callback_server)
|
31
|
+
Thread.new do
|
32
|
+
Thread.new(callback_server.accept) do |callback_conn|
|
33
|
+
message = JSON.parse(callback_conn.gets, symbolize_names: true)
|
34
|
+
runtime = @runtimes[message[:session_id]]
|
35
|
+
runtime.start(message[:pid])
|
36
|
+
$stdout.puts "Runtime ready at port #{runtime.port.to_s}"
|
37
|
+
callback_conn.close
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def start
|
43
|
+
loop { async_new_repl_connections }
|
44
|
+
end
|
45
|
+
|
46
|
+
def shutdown
|
47
|
+
@runtimes.each do |id, runtime|
|
48
|
+
$stdout.puts runtime.inspect
|
49
|
+
$stdout.puts ("shutdown"+runtime.port.to_s).inspect
|
50
|
+
runtime.shutdown
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Input
|
55
|
+
def initialize(input)
|
56
|
+
@input = input
|
57
|
+
end
|
58
|
+
def read
|
59
|
+
begin
|
60
|
+
context = Rapel.runtimes.first[1]
|
61
|
+
expression = Rapel::Expression.new(@input.slice(:code))
|
62
|
+
expression
|
63
|
+
rescue Exception => e
|
64
|
+
$stdout.puts(e.inspect)
|
65
|
+
end
|
66
|
+
$stdout.puts("Input read: #{expression.inspect}")
|
67
|
+
yield expression, context
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rapel
|
2
|
+
|
3
|
+
class Runtime
|
4
|
+
|
5
|
+
attr_reader :session_id, :port
|
6
|
+
attr_accessor :socket
|
7
|
+
|
8
|
+
def initialize(callback_port, session_id)
|
9
|
+
runtime_port = 9220
|
10
|
+
@port = runtime_port
|
11
|
+
@session_id = session_id
|
12
|
+
system(ruby_runtime_string(callback_port))
|
13
|
+
end
|
14
|
+
|
15
|
+
def ruby_runtime_string(callback_port)
|
16
|
+
["ruby #{File.dirname(__FILE__)}/../../bin/runtime.rb",
|
17
|
+
"--port=#{port}",
|
18
|
+
"--callback-port=#{callback_port}",
|
19
|
+
"--uuid=#{session_id}",
|
20
|
+
"&"].join(" ")
|
21
|
+
end
|
22
|
+
|
23
|
+
def shutdown
|
24
|
+
puts "killing at port #{port}"
|
25
|
+
socket.puts("shutdown"+port.to_s)
|
26
|
+
rescue
|
27
|
+
puts "killing pid #{@pid}"
|
28
|
+
`kill -9 #{@pid}`
|
29
|
+
end
|
30
|
+
|
31
|
+
def start(pid)
|
32
|
+
@pid = pid
|
33
|
+
@ready = true
|
34
|
+
@socket = TCPSocket.new('localhost', port)
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
"\#<Runtime @session=\"#@session_id\" @ready=#@ready>"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/rapel/version.rb
CHANGED
data/rapel.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["nicklink483@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{Multi-client, multi-runtime REPL Server}
|
13
|
-
spec.description = %q{Rapel provides a multi-client, multi-runtime REPL server which accepts incoming expressions, e.g. 2+2, evaluates them in a runtime, and returns the result, e.g. 4.}
|
13
|
+
spec.description = %q{Rapel (ruh-PELL) provides a multi-client, multi-runtime REPL server which accepts incoming expressions, e.g. 2+2, evaluates them in a runtime, and returns the result, e.g. 4.}
|
14
14
|
spec.homepage = "https://github.com/domgetter/rapel"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rapel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominic Muller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,9 +52,9 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
description: Rapel provides a multi-client, multi-runtime REPL server which
|
56
|
-
incoming expressions, e.g. 2+2, evaluates them in a runtime, and returns
|
57
|
-
e.g. 4.
|
55
|
+
description: Rapel (ruh-PELL) provides a multi-client, multi-runtime REPL server which
|
56
|
+
accepts incoming expressions, e.g. 2+2, evaluates them in a runtime, and returns
|
57
|
+
the result, e.g. 4.
|
58
58
|
email:
|
59
59
|
- nicklink483@gmail.com
|
60
60
|
executables: []
|
@@ -69,8 +69,12 @@ files:
|
|
69
69
|
- README.md
|
70
70
|
- Rakefile
|
71
71
|
- bin/console
|
72
|
+
- bin/runtime.rb
|
72
73
|
- bin/setup
|
73
74
|
- lib/rapel.rb
|
75
|
+
- lib/rapel/expression.rb
|
76
|
+
- lib/rapel/replserver.rb
|
77
|
+
- lib/rapel/runtime.rb
|
74
78
|
- lib/rapel/version.rb
|
75
79
|
- rapel.gemspec
|
76
80
|
homepage: https://github.com/domgetter/rapel
|