-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.rb
113 lines (93 loc) · 3.19 KB
/
server.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
require 'socket'
require 'open3'
module CowSay
class Server
def initialize(port)
# Create the underlying socket server
@server = TCPServer.new(port)
puts "Listening on port #{@server.local_address.ip_port}"
end
def start
# TODO Currently this server can only accept one connection at at
# time. Do I want to change that so I can process multiple requests
# at once?
Socket.accept_loop(@server) do |connection|
handle(connection)
connection.close
end
end
# Find a value in a line for a given key
def find_value_for_key(key, document)
retval = nil
re = /^#{key} (.*)/
md = re.match(document)
if md != nil
retval = md[1]
end
retval
end
# Parse the request that is sent by the client and convert it into a
# hash table.
def parse(request)
commands = Hash.new
commands[:error_flag] = false
# TODO It's still possible to pass a non-message
# value like -h or -l as a message. It would be nice
# to sanitize your input.
message_value = find_value_for_key("MESSAGE", request)
if message_value == nil then
commands[:message] = "ERROR: Empty message"
commands[:error_flag] = true
else
commands[:message] = message_value
end
body_value = find_value_for_key("BODY", request)
if body_value == nil then
commands[:body] = "default"
else
commands[:body] = body_value
end
commands
end
def handle(connection)
begin
request = connection.read_nonblock(4096)
rescue Errno::EAGAIN
puts "got here"
IO.select([connection])
retry
end
commands = parse(request)
if commands[:error_flag] then
# We got an error parsing the message, time to bail out.
respond(connection, 1, commands[:message])
else
exit_status, output = process(commands)
respond(connection, exit_status, output)
end
end
def respond(connection, exit_status, message)
connection.write <<EOF
STATUS #{exit_status}
#{message}
EOF
end
def process(commands)
output = nil
err_msg = nil
exit_status = nil
Open3.popen3('/usr/games/cowsay', '-f', commands[:body], commands[:message]) { |stdin, stdout, stderr, wait_thr|
# TODO Do I need to wait for the process to complete?
output = stdout.read
err_msg = stderr.read
exit_status = wait_thr.value.exitstatus
}
if exit_status != 0 then
output = "ERROR #{err_msg}"
end
return exit_status, output
end
end
end
server = CowSay::Server.new(4481)
server.start