rapel 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87d7d40d72f64667ac13d584c0047f8d4aa511c3
4
- data.tar.gz: de2243f93bdf36fa4e79547b3b828f6208c84e19
3
+ metadata.gz: b92563a1ed6631d218e18f28bdae877f2fc9d871
4
+ data.tar.gz: a6a5260a12414bf9741af4119225c2aa6670d881
5
5
  SHA512:
6
- metadata.gz: b0fd44fdef4b60ea1cc04789a152baec11e0c26a9aae2fc7236b8ac97a209ebc6394b1dad22b3ab11f7ea4b2815f1402b4569256af90a6c6c14aeb9911e9f916
7
- data.tar.gz: de1d3a0be60e1344776edaca50ba39db6d13a37dafe61e0a42e6f380e84292130f4d1be42aa3e1606ff7dd1abba6cae247ddaa020cd8d0570a776ce0f63d52ff
6
+ metadata.gz: 6b67829358e692e0d1d10869537aca3b8292cd73733e7721464067c4c744198be3ea4d50b62b5345767b8e00c6a84bf547e2f1d338674752b469ad99f7629186
7
+ data.tar.gz: 4d27177c6ded616ace9ac0e74a2f06ad7d27f4d5374d48eb6b168332ee85190a2cd7a92625400cd41e17ca7f7fdf9cc0c8b19633aa1b892a12be55608f3c0b76
data/.gitignore CHANGED
@@ -7,3 +7,6 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.gem
11
+ bin/runtime.log
12
+ tags
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Rapel
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rapel`. To experiment with that code, run `bin/console` for an interactive prompt.
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/[USERNAME]/rapel.
36
-
33
+ Bug reports and pull requests are welcome on GitHub at https://github.com/domgetter/rapel.
37
34
 
38
35
  ## License
39
36
 
@@ -10,5 +10,6 @@ require "rapel"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
14
- IRB.start
13
+ Rapel.start
14
+ # require "irb"
15
+ # IRB.start
@@ -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
+
@@ -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
- # Your code goes here...
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
@@ -1,3 +1,3 @@
1
1
  module Rapel
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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.1.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-14 00:00:00.000000000 Z
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 accepts
56
- incoming expressions, e.g. 2+2, evaluates them in a runtime, and returns the result,
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