Reputation: 1627
I need some hints/help, how can I read multiline response into variable. My current command results me multiline response but after that I get timeout.
Here's how my connection is setup:
connection = Net::Telnet.new('Host' => host,'Port' => 4800, 'Telnetmode' => false, 'Timeout' => 1)
Here's my request and how I save it:
puts "Weather request\n"
connection.cmd("{weather}"){ |c| print c }
parsed = JSON.parse(str)
puts "#{parsed}\n\n"
And here's the error:
/usr/lib/ruby/1.9.1/net/telnet.rb:558:in `waitfor': timed out while waiting for more data (Timeout::Error)
from /usr/lib/ruby/1.9.1/net/telnet.rb:695:in `cmd'
from ruby_check.rb:37:in `<main>'
My response is multiple JSON lines, like this:
{"City":"Tallinn", "Degrees":"23"}
{"City":"Berlin", "Degrees":"23"}
{"City":"Helsinki", "Degrees":"23"}
{"City":"Stockholm", "Degrees":"23"}
Upvotes: 4
Views: 1048
Reputation: 30143
The Net::Telnet
documentation says:
For some protocols, it will be possible to specify the Prompt option once when you create the Telnet object and use cmd() calls; for others, you will have to specify the response sequence to look for as the Match option to every cmd() call, or call puts() and waitfor() directly; for yet others, you will have to use sysread() instead of waitfor() and parse server responses yourself.
This makes more sense when combined with the Net::Telnet#cmd
method's documentation, which says that the method:
sends a string to the host, and reads in all received data until is sees the prompt or other matched sequence.
You're not specifying a custom Prompt
or Match
option, so #cmd
is waiting for something from the server that matches the default Net::Telnet
prompt (/[$%#>] \z/n
) to indicate the end of the message.
If the message doesn't end with that kind of prompt, then it'll be waiting forever.
If the server does send some kind of prompt to indicate it's finished sending data and you should type the next command, you can pass a regular expression that matches it to the Net::Telnet
initialiser. For example, if the server prompted you with command:
, you could use:
connection = Net::Telnet.new(
"Prompt" => /command: \z/,
# …
)
If there's no prompt, but the response you're waiting for ends with a specific character sequence, you could explicitly specify the Match
option when you call #cmd
. For example, if your response was a single JSON array it would end with ]
, so you might be able to use this:
connection.cmd("String" => "{weather}", "Match" => "]") { |c| print c }
Net::Telnet
and use a TCPSocket
If there's no prompt and no known ending, you could try to use the Net::Telnet
object's underlying TCPSocket
to read the data without using #cmd
:
connection.puts("{weather}")
connection.sock.readline
At this point, there might not be much benefit to using Net::Telnet
over a plain TCPSocket
.
Upvotes: 3
Reputation: 3724
You are setting the timeout to one second and do not specify what str
is. You can try increasing the timeout value or even setting it to false. Believieng it is the result from .cmd
, try this:
connection = Net::Telnet.new(
"Host" => host, "Port" => 4800,
"Telnetmode" => false, "Timeout" => false)
puts "Weather request...\n"
str = connection.cmd("{weather}"){ |c| print c }
parsed = JSON.parse(str)
puts "#{parsed}\n\n"
Upvotes: 1