ruby_robot 0.1.9
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 +7 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +133 -0
- data/Guardfile +77 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/Rakefile +24 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/ruby_robot +34 -0
- data/exe/ruby_robot_grpc_client +53 -0
- data/exe/ruby_robot_grpc_server +46 -0
- data/exe/ruby_robot_web +19 -0
- data/json_schema/request.schema.json +37 -0
- data/json_schema/response.schema.json +24 -0
- data/lib/public/favicon-16x16.png +0 -0
- data/lib/public/favicon-32x32.png +0 -0
- data/lib/public/index.html +95 -0
- data/lib/public/swagger-ui-bundle.js +93 -0
- data/lib/public/swagger-ui-standalone-preset.js +13 -0
- data/lib/public/swagger-ui.css +3 -0
- data/lib/public/swagger-ui.js +8 -0
- data/lib/public/swagger.json +179 -0
- data/lib/ruby_robot.rb +16 -0
- data/lib/ruby_robot/cacerts.crt +92 -0
- data/lib/ruby_robot/construction_error.rb +4 -0
- data/lib/ruby_robot/grpc/robot_service.rb +102 -0
- data/lib/ruby_robot/grpc/ruby_robot_services_pb.rb +34 -0
- data/lib/ruby_robot/grpc_helper.rb +15 -0
- data/lib/ruby_robot/grpc_ruby/ruby_robot_pb.rb +36 -0
- data/lib/ruby_robot/grpc_shell.rb +85 -0
- data/lib/ruby_robot/netflix_tabletop.rb +14 -0
- data/lib/ruby_robot/placement_error.rb +4 -0
- data/lib/ruby_robot/robot.rb +71 -0
- data/lib/ruby_robot/ruby_robot.proto +53 -0
- data/lib/ruby_robot/schema_loader.rb +10 -0
- data/lib/ruby_robot/shell.rb +204 -0
- data/lib/ruby_robot/tabletop.rb +120 -0
- data/lib/ruby_robot/version.rb +3 -0
- data/lib/ruby_robot/webapp.rb +263 -0
- data/ruby_robot.gemspec +48 -0
- metadata +258 -0
data/lib/ruby_robot.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "ruby_robot/version"
|
2
|
+
require "ruby_robot/tabletop"
|
3
|
+
require "ruby_robot/netflix_tabletop"
|
4
|
+
require "ruby_robot/robot"
|
5
|
+
require "ruby_robot/construction_error"
|
6
|
+
require "ruby_robot/schema_loader"
|
7
|
+
require "ruby_robot/placement_error"
|
8
|
+
require "ruby_robot/shell"
|
9
|
+
require "ruby_robot/webapp"
|
10
|
+
require "ruby_robot/grpc_helper"
|
11
|
+
require "ruby_robot/grpc_shell"
|
12
|
+
require "ruby_robot/grpc_ruby/ruby_robot_pb"
|
13
|
+
require 'ruby_robot/grpc_helper'
|
14
|
+
|
15
|
+
module RubyRobot
|
16
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
3
|
+
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
4
|
+
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
5
|
+
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
6
|
+
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
7
|
+
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
8
|
+
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
9
|
+
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
10
|
+
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
11
|
+
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
12
|
+
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
13
|
+
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
14
|
+
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
15
|
+
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
16
|
+
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
17
|
+
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
18
|
+
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
19
|
+
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
20
|
+
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
21
|
+
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
22
|
+
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
23
|
+
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
24
|
+
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
25
|
+
-----END CERTIFICATE-----
|
26
|
+
-----BEGIN CERTIFICATE-----
|
27
|
+
MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
|
28
|
+
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
|
29
|
+
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
|
30
|
+
eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
|
31
|
+
gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
32
|
+
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
|
33
|
+
VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
|
34
|
+
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
|
35
|
+
AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
|
36
|
+
2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
|
37
|
+
ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
|
38
|
+
4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
|
39
|
+
m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
|
40
|
+
vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
|
41
|
+
8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
|
42
|
+
IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
|
43
|
+
KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
|
44
|
+
GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
|
45
|
+
s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
|
46
|
+
JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
|
47
|
+
AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
|
48
|
+
MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
|
49
|
+
bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
|
50
|
+
Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
|
51
|
+
zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
|
52
|
+
Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
|
53
|
+
Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
|
54
|
+
B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
|
55
|
+
PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
|
56
|
+
pu/xO28QOG8=
|
57
|
+
-----END CERTIFICATE-----
|
58
|
+
-----BEGIN CERTIFICATE-----
|
59
|
+
MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB
|
60
|
+
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
61
|
+
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
|
62
|
+
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy
|
63
|
+
MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
|
64
|
+
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
|
65
|
+
Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh
|
66
|
+
bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
67
|
+
ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh
|
68
|
+
bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0
|
69
|
+
Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6
|
70
|
+
ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51
|
71
|
+
UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n
|
72
|
+
c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY
|
73
|
+
MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz
|
74
|
+
30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV
|
75
|
+
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG
|
76
|
+
BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv
|
77
|
+
bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB
|
78
|
+
AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E
|
79
|
+
T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v
|
80
|
+
ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p
|
81
|
+
mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/
|
82
|
+
e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps
|
83
|
+
P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY
|
84
|
+
dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc
|
85
|
+
2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG
|
86
|
+
V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4
|
87
|
+
HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX
|
88
|
+
j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII
|
89
|
+
0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap
|
90
|
+
lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf
|
91
|
+
+AZxAeKCINT+b72x
|
92
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'grpc'
|
3
|
+
# Tweak the load path so ruby_robot_services_pb can
|
4
|
+
# load ruby_robot_pb
|
5
|
+
$: << File.dirname(__FILE__) + '/../grpc_ruby'
|
6
|
+
require 'ruby_robot/grpc/ruby_robot_services_pb'
|
7
|
+
require 'logger'
|
8
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
|
9
|
+
require 'ruby_robot'
|
10
|
+
|
11
|
+
module RubyRobot
|
12
|
+
module Grpc
|
13
|
+
class RobotService < ::RubyRobot::RubyRobot::Service
|
14
|
+
def logger
|
15
|
+
@logger ||= proc {
|
16
|
+
Logger.new(STDOUT)
|
17
|
+
}.call
|
18
|
+
end
|
19
|
+
|
20
|
+
def robot
|
21
|
+
@@robot ||= proc {
|
22
|
+
rr = ::RubyRobot::Shell.new
|
23
|
+
def rr.placed?
|
24
|
+
!@robot.nil?
|
25
|
+
end
|
26
|
+
rr
|
27
|
+
}.call
|
28
|
+
end
|
29
|
+
|
30
|
+
def not_placed_error
|
31
|
+
::RubyRobot::RubyRobotResponse.new(
|
32
|
+
error: ::RubyRobot::RubyRobotError.new(error: 400, message: "Robot is not currently placed")
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def position_report
|
37
|
+
rr = robot.REPORT(false)
|
38
|
+
|
39
|
+
::RubyRobot::RubyRobotResponse.new(
|
40
|
+
current_state: ::RubyRobot::RubyRobotRequest.new(
|
41
|
+
x: rr[:x],
|
42
|
+
y: rr[:y],
|
43
|
+
direction: rr[:direction].to_s.upcase.to_sym
|
44
|
+
)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def left(empty, _unused_call)
|
49
|
+
logger.info "#{__method__} called (robot.placed?==#{robot.placed?})"
|
50
|
+
if robot.placed?
|
51
|
+
robot.LEFT
|
52
|
+
position_report
|
53
|
+
else
|
54
|
+
not_placed_error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def move(empty, _unused_call)
|
59
|
+
logger.info "#{__method__} called (robot.placed?==#{robot.placed?})"
|
60
|
+
if robot.placed?
|
61
|
+
robot.MOVE
|
62
|
+
position_report
|
63
|
+
else
|
64
|
+
not_placed_error
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def place(robot_request, _unused_call)
|
69
|
+
input = { x: robot_request.x, y: robot_request.y, direction: robot_request.direction }
|
70
|
+
logger.info "#{__method__} called with #{input.to_json}"
|
71
|
+
|
72
|
+
robot.PLACE(robot_request.x, robot_request.y, robot_request.direction.to_s.downcase)
|
73
|
+
position_report
|
74
|
+
end
|
75
|
+
|
76
|
+
def remove(empty, _unused_call)
|
77
|
+
logger.info "#{__method__} called"
|
78
|
+
@@robot = nil
|
79
|
+
::Google::Protobuf::Empty.new
|
80
|
+
end
|
81
|
+
|
82
|
+
def report(empty, _unused_call)
|
83
|
+
logger.info "#{__method__} called (robot.placed?==#{robot.placed?})"
|
84
|
+
if robot.placed?
|
85
|
+
position_report
|
86
|
+
else
|
87
|
+
not_placed_error
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def right(empty, _unused_call)
|
92
|
+
logger.info "#{__method__} called (robot.placed?==#{robot.placed?})"
|
93
|
+
if robot.placed?
|
94
|
+
robot.RIGHT
|
95
|
+
position_report
|
96
|
+
else
|
97
|
+
not_placed_error
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# Source: ruby_robot.proto for package 'RubyRobot'
|
3
|
+
# Original file comments:
|
4
|
+
#
|
5
|
+
# gRPC service definition for the RubyRobot.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'grpc'
|
9
|
+
require 'ruby_robot_pb'
|
10
|
+
|
11
|
+
module RubyRobot
|
12
|
+
module RubyRobot
|
13
|
+
#
|
14
|
+
# Service definitions
|
15
|
+
#
|
16
|
+
class Service
|
17
|
+
|
18
|
+
include GRPC::GenericService
|
19
|
+
|
20
|
+
self.marshal_class_method = :encode
|
21
|
+
self.unmarshal_class_method = :decode
|
22
|
+
self.service_name = 'RubyRobot.RubyRobot'
|
23
|
+
|
24
|
+
rpc :Left, Google::Protobuf::Empty, RubyRobotResponse
|
25
|
+
rpc :Move, Google::Protobuf::Empty, RubyRobotResponse
|
26
|
+
rpc :Place, RubyRobotRequest, RubyRobotResponse
|
27
|
+
rpc :Remove, Google::Protobuf::Empty, Google::Protobuf::Empty
|
28
|
+
rpc :Report, Google::Protobuf::Empty, RubyRobotResponse
|
29
|
+
rpc :Right, Google::Protobuf::Empty, RubyRobotResponse
|
30
|
+
end
|
31
|
+
|
32
|
+
Stub = Service.rpc_stub_class
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ruby_robot/grpc_ruby/ruby_robot_pb'
|
2
|
+
#
|
3
|
+
# Define #to_json on ::RubyRobot::RubyRobotRequest for prettier printing.
|
4
|
+
#
|
5
|
+
module RubyRobot
|
6
|
+
class RubyRobotRequest
|
7
|
+
def to_json
|
8
|
+
{
|
9
|
+
x: self.x,
|
10
|
+
y: self.y,
|
11
|
+
direction: self.direction.to_s
|
12
|
+
}.to_json
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: ruby_robot.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require 'google/protobuf/empty_pb'
|
7
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
8
|
+
add_message "RubyRobot.RubyRobotRequest" do
|
9
|
+
optional :x, :int32, 1
|
10
|
+
optional :y, :int32, 2
|
11
|
+
optional :direction, :enum, 3, "RubyRobot.RubyRobotRequest.Direction"
|
12
|
+
end
|
13
|
+
add_enum "RubyRobot.RubyRobotRequest.Direction" do
|
14
|
+
value :NORTH, 0
|
15
|
+
value :EAST, 1
|
16
|
+
value :SOUTH, 2
|
17
|
+
value :WEST, 3
|
18
|
+
end
|
19
|
+
add_message "RubyRobot.RubyRobotError" do
|
20
|
+
optional :error, :int32, 1
|
21
|
+
optional :message, :string, 2
|
22
|
+
end
|
23
|
+
add_message "RubyRobot.RubyRobotResponse" do
|
24
|
+
oneof :response do
|
25
|
+
optional :current_state, :message, 1, "RubyRobot.RubyRobotRequest"
|
26
|
+
optional :error, :message, 2, "RubyRobot.RubyRobotError"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module RubyRobot
|
32
|
+
RubyRobotRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("RubyRobot.RubyRobotRequest").msgclass
|
33
|
+
RubyRobotRequest::Direction = Google::Protobuf::DescriptorPool.generated_pool.lookup("RubyRobot.RubyRobotRequest.Direction").enummodule
|
34
|
+
RubyRobotError = Google::Protobuf::DescriptorPool.generated_pool.lookup("RubyRobot.RubyRobotError").msgclass
|
35
|
+
RubyRobotResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("RubyRobot.RubyRobotResponse").msgclass
|
36
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'bombshell'
|
2
|
+
require 'logger'
|
3
|
+
require 'ruby_robot/shell'
|
4
|
+
require 'ruby_robot/grpc_helper'
|
5
|
+
$: << File.dirname(__FILE__) + '/grpc_ruby'
|
6
|
+
require 'ruby_robot/grpc/ruby_robot_services_pb'
|
7
|
+
|
8
|
+
module RubyRobot
|
9
|
+
#
|
10
|
+
# Override all methods inherited from Shell
|
11
|
+
# such that they use gRPC to communicate
|
12
|
+
# with a remote Robot.
|
13
|
+
#
|
14
|
+
# TODO: RPC error handling (more info at
|
15
|
+
# https://grpc.io/docs/guides/error.html).
|
16
|
+
#
|
17
|
+
class GrpcShell < ::Bombshell::Environment
|
18
|
+
include ::Bombshell::Shell
|
19
|
+
|
20
|
+
prompt_with 'ILoveNetflixStudio&gRPC'
|
21
|
+
|
22
|
+
# TODO: Figure out if there's a way to pass args down into
|
23
|
+
# ::Bombshell#launch so this isn't a class attr.
|
24
|
+
def self.remote_url=(new_url)
|
25
|
+
# Convert to URI if String
|
26
|
+
@@remote_url = new_url.kind_of?(String) ? URI.parse(new_url) : new_url
|
27
|
+
end
|
28
|
+
def initialize
|
29
|
+
# TODO: Enable SSL/TLS
|
30
|
+
# Totally cheating here: if URI is grpc://netflix.avilla.net,
|
31
|
+
# then load up the cert (stored in the gem).
|
32
|
+
if @@remote_url.to_s.start_with?("grpcs://netflix.avilla.net")
|
33
|
+
ca_path = File.join(File.dirname(__FILE__), "cacerts.crt")
|
34
|
+
channel_creds = GRPC::Core::ChannelCredentials.new(File.read(ca_path))
|
35
|
+
stub_opts = {
|
36
|
+
:creds => channel_creds,
|
37
|
+
GRPC::Core::Channel::SSL_TARGET => @@remote_url.host
|
38
|
+
}
|
39
|
+
@stub = ::RubyRobot::RubyRobot::Stub.new(
|
40
|
+
"#{@@remote_url.host}:#{@@remote_url.port}", channel_creds
|
41
|
+
)
|
42
|
+
else
|
43
|
+
@stub = ::RubyRobot::RubyRobot::Stub.new("#{@@remote_url.host}:#{@@remote_url.port}", :this_channel_is_insecure)
|
44
|
+
end
|
45
|
+
puts "Checking state of Robot at #{@@remote_url}"
|
46
|
+
self.REPORT()
|
47
|
+
end
|
48
|
+
|
49
|
+
def PLACE(x, y, direction)
|
50
|
+
@stub.place(::RubyRobot::RubyRobotRequest.new(x: x, y: y, direction: direction.to_s.upcase.to_sym))
|
51
|
+
end
|
52
|
+
|
53
|
+
def MOVE
|
54
|
+
@stub.move(Google::Protobuf::Empty.new)
|
55
|
+
end
|
56
|
+
|
57
|
+
def LEFT
|
58
|
+
@stub.left(Google::Protobuf::Empty.new)
|
59
|
+
end
|
60
|
+
|
61
|
+
def RIGHT
|
62
|
+
@stub.right(Google::Protobuf::Empty.new)
|
63
|
+
end
|
64
|
+
|
65
|
+
def REPORT(to_stderr=false)
|
66
|
+
resp = @stub.report(Google::Protobuf::Empty.new)
|
67
|
+
if resp.error
|
68
|
+
puts resp.error.message
|
69
|
+
else
|
70
|
+
puts resp.current_state.to_json
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def REMOVE
|
75
|
+
@stub.remove(Google::Protobuf::Empty.new)
|
76
|
+
end
|
77
|
+
|
78
|
+
alias :QUIT :quit
|
79
|
+
end
|
80
|
+
end
|
81
|
+
module Bombshell
|
82
|
+
module Shell
|
83
|
+
REMOVE=:remove
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module RubyRobot
|
2
|
+
class Robot
|
3
|
+
|
4
|
+
# Directions are clockwise from north
|
5
|
+
VALID_DIRECTIONS = [:north, :east, :south, :west]
|
6
|
+
|
7
|
+
attr_reader :direction
|
8
|
+
attr_reader :tabletop
|
9
|
+
|
10
|
+
def initialize(direction)
|
11
|
+
orig_direction = direction
|
12
|
+
err_msg = "New Robots must have direction value of one of the following symbols: #{VALID_DIRECTIONS.join(', ')}; invalid value '#{orig_direction}'"
|
13
|
+
direction = direction.kind_of?(String) ? direction.downcase.to_sym : direction
|
14
|
+
raise ConstructionError.new(err_msg) unless VALID_DIRECTIONS.include?(direction)
|
15
|
+
@direction = direction
|
16
|
+
@tabletop = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
case @direction
|
21
|
+
when :north then "^"
|
22
|
+
when :south then "|"
|
23
|
+
when :east then ">"
|
24
|
+
# :west
|
25
|
+
else "<"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def left
|
30
|
+
# A little cheating here...index -1 will effectively wrap around and
|
31
|
+
# return the last element
|
32
|
+
@direction = VALID_DIRECTIONS[dir_idx - 1]
|
33
|
+
end
|
34
|
+
|
35
|
+
def right
|
36
|
+
@direction = VALID_DIRECTIONS[(dir_idx + 1) % VALID_DIRECTIONS.size]
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Called by a Tabletop where this has been placed
|
41
|
+
#
|
42
|
+
def place(tabletop)
|
43
|
+
@tabletop = tabletop
|
44
|
+
end
|
45
|
+
|
46
|
+
def report
|
47
|
+
@tabletop.position(self).merge(direction: direction)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# TODO: Error checking for if @tabletop.nil?
|
52
|
+
# Also, @tabletop.move and @tabletop.move? together
|
53
|
+
# should be synchronized if multithreaded where > 1
|
54
|
+
# Robot are on a Tabletop.
|
55
|
+
#
|
56
|
+
# Return #report after call, whether it was successful
|
57
|
+
# or not (assuming it _is_ in fact placed on a board).
|
58
|
+
#
|
59
|
+
def move
|
60
|
+
@tabletop.move(self, direction) if @tabletop.move?(self, direction)
|
61
|
+
report
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def dir_idx
|
67
|
+
VALID_DIRECTIONS.index(@direction)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|