Using WebSockets with EM and IRC to Send "Connection Successful" Message - ruby

I'm attempting to write an IRC client using WebSockets. The IRC client I found on GitHub uses EventMachine, but I'm trying to use WebSockets as well to notify any connected clients when they're connected. However, I don't think I'm quite understanding EventMachine, because although the client successfully connects and joins the IRC channel, the puts 'Connected...' nor the subsequent line gets executed.
I assume this is because of a fundamental misunderstanding of EventMachine on my behalf.
EM.run {
EventMachine::WebSocket.start(:host => '0.0.0.0', :port => 8080) do |websocket|
websocket.onopen {
irc = Net::YAIL.new(
:address => 'irc.my-example-server.net',
:port => 6667,
:username => 'MyExample',
:realname => 'My Example Bot',
:nicknames => ['MyExample1', 'MyExample2', 'MyExample3']
)
irc.on_welcome proc { |event|
irc.join('#ExampleChannel')
EM.next_tick {
puts 'Connected...'
websocket.send({ :message => 'Connected' })
}
}
irc.start_listening!
}
end
}

I think I've answered my own question after a night of research. Essentially it has nothing to do with my misunderstanding of EventMachine. It's just the IRC client I was attempting to use was simply an infinite loop, and therefore nothing else could interrupt it. After researching for a further couple of hours for an EventMachine compatible IRC client, I came across Ponder: https://github.com/tbuehlmann/ponder so now hopefully I can continue creating my application!
Shameless plug: https://github.com/Wildhoney/Banter.js

Related

Ruby background TCP Server

I wish to create a TCPServer which listens in the background while the script continues it's normal execution.
For example-
server=TCPServer.open(srvhost,srvport)
client=server.accept
res=send_request_cgi({
'uri' => "/",
'method' => 'GET',
'vars_get' =>
'cmd' => rand_text_alphanumeric(10)
}
})
print "#{res.headers}"
data=client.recv(1024)
puts data
client.close
This pauses the script at the listener.
Objective-The server will always receive a response on srvport which it should print.
Edit-
webserv=Thread.new do
server=TCPServer.new(srvhost,srvport)
client=server.accept
data=client.recv(1024)
if(data.empty?)
puts 'nope'
client.close
server.close
webserv.exit
end
puts data
client.write(cmd)
client.close
server.close
webserv.exit
end
You can put your server in a new Thread with
websrv = Thread.new do
<your server logic> # Main server loop, handle data, etc.
ensure
<your cleanup code> # Close connections, files, etc.
end
<application code>
websrv.join # wait for web server to do its thing
Needless to say, in ruby you'd usually wrap that in some sort of BackgroundServer class, but the basic idea is the same.
Note that rubys threads don't really execute in parallel; the interpreter just takes care of switching back and forth between them.

Telnet - EventMachine, Theaded?

I have a project where I need to update multiple thousands of devices with a series of commands via telnet. The commands will not brick or cause the device to go offline (login, apply commands, logout).
I use snmp4em extensively where SNMP is applicable. A blocking approach here would take forever.
I am not well versed with Threading, EventMachine (at its core), etc., to attempt to approach this from scratch.
I have been looking at em-simple_telnet. It appears to have the functionality I need, my problem is the error coding. If a host isn't reachable or fails login, it throws an error at the top-most level of the code (EventMachine.run do), which I've found difficult to rescue.
Maybe I'm having a blond-moment but I'm not seeing the solution. The following code works as long as there is no failure.
require 'em-simple_telnet'
File.delete('/tmp/telnetDebug.log') if File.exists?('/tmp/telnetDebug.log')
begin
EventMachine.run do
['device1', 'device2_will_fail', 'device3'].each do |h|
opts = {
host: h,
username: "user",
password: "pass",
binmode: true,
telnetmode: true,
login_prompt: /[$%#:>]\s\z/n,
password_prompt: /[$%#:>]\s\z/n,
prompt: /[$%#:>]\s?\z/n,
output_log: "/tmp/telnetDebug.log",
}
EM::P::SimpleTelnet.new(opts) do |host|
# already logged in
puts "Connected"
puts host.cmd('cmd1') { |c| puts c }
puts host.cmd('cmd2') { |c| puts c }
puts host.cmd("exit") { |c| puts c }
end
end
end
rescue Exception => e
puts e.inspect
end
me#WorkStation:~/ruby_workspace/modem_updates$ ruby modem_update_em.rb
#<EventMachine::Protocols::SimpleTelnet::LoginFailed: Timed out while expecting some kind of prompt.>
I'm reaching out to those that would have experience in this area and could offer some possible solutions to my problem. Can someone offer a suggestion as to how to recover from error (shown below)? Or perhaps another approach? Your expertise is most appreciated.

Rabbitmq queuing system not being consumed using fanout

ive been trying to fanout those queues using a ruby consumer very simple it just subscribes to that exchange/queues and it receives the message. now the problem whenever a new message is published. they dont receive the message which means they are not consuming and no consumers are listed. once you rebind the queue with the exchange again and restart the ruby app it starts to consume again. then it goes back to lembo again! sometimes when you restart the ruby app for few times it works. any idea?
code used for the consumer below:
#!/usr/bin/env ruby
# encoding: utf-8
require "rubygems"
require "amqp"
EventMachine.run do
connection = AMQP.connect(:host => '127.0.0.1', :port => 5672, :user => "user",:pass => "pass",:vhost => "/",:ssl => false,:frame_max => 131072 )
puts "Connected to AMQP broker. Running #{AMQP::VERSION} version of the gem..."
channel = AMQP::Channel.new(connection)
exchange = channel.fanout("p_cmds.p1")
channel.queue("p1_queue").bind(exchange).subscribe do |payload|
puts "#{payload} => p1"
end
end

Ruby HttpClient async

Hello stack overflow people.
Does someone know of a code example to make the ruby httpclient do an async post? It has a method but it looks like it just gives you a connection back you have to keep checking, which I assume would still be blocking. I did not see a way to "fire and forget" or just pass a method that it could call later in a separate thread while the rest of my code kept running.
thanks,
craig
This sounds like you're programming in evented style. Maybe you are even using eventmachine? You don't say so, but in the case you do, this project: https://github.com/eventmachine/em-http-request will let you do something close:
EventMachine.run {
http = EventMachine::HttpRequest.new('http://127.0.0.1/').get :query => {'keyname' => 'value'}
http.callback {
p http.response_header.status
p http.response_header
p http.response
EventMachine.stop
}
}

Ruby SOAP SSL Woes

I have a SOAP client in Ruby that I'm trying to get working with a Ruby SOAP server, to no avail. The client works fine over SSL with a Python SOAP server, but not with the Ruby version. Here's what the server looks like:
require 'soap/rpc/standaloneServer'
require 'soap/rpc/driver'
require 'rubygems'
require 'httpclient'
def cert(filename)
OpenSSL::X509::Certificate.new(File.open("path to cert.cert") { |f|
f.read
})
end
def key(filename)
OpenSSL::PKey::RSA.new(File.open("path to rsaprivate.key") { |f|
f.read
})
end
class Server < SOAP::RPC::HTTPServer
~code snipped for readability~
end
server = Server.new(:BindAddress => HelperFunctions.local_ip, :Port => 1234, :SSLCertificate => cert("path to cert"), :SSLPrivateKey => key("path to rsa private key"))
new_thread = Thread.new { server.start }
I've trimmed some of the code out for readability's sake (e.g., I have some methods in there I expose) and it works fine with SSL off. But when the client tries to connect, it sees this:
warning: peer certificate won't be verified in this SSL session
/usr/lib/ruby/1.8/net/http.rb:567: warning: using default DH parameters.
/usr/lib/ruby/1.8/net/http.rb:586:in `connect': unknown protocol (OpenSSL::SSL::SSLError)
I tried taking some advice from this post and now I see this message:
/usr/lib/ruby/1.8/soap/httpconfigloader.rb:64:in `set_ssl_config': SSL not supported (NotImplementedError)
Any ideas on how to fix this would be greatly appreciated.
Arg. I was trying to follow along this link and it turns out I was missing a simple include statement:
require 'webrick/https'
That, combined with the help from the link in the original question solves the problem. Hopefully this saves someone else down the line an hour of grief :)
"SSL not supported" can be caused by not having httpclient installed.
Me too.. and don't forget to put the :SSLEnable => true spend couple of hours figuring that out...
server = Server.new(:BindAddress => HelperFunctions.local_ip, :Port => 1234, :SSLEnable => true, :SSLCertificate => cert("path to cert"), :SSLPrivateKey => key("path to rsa private key"))

Resources