Get online users XMPP4r + Rails - ruby-on-rails

I'm trying get online friends by user in XMPP server (Ejabberd). I'm using Ruby on Rails 3.2.
The idea is to add in array all online users to use this on view page.
I found asynchronous code (below), but it use Thread and it's difficult to work on controller method.
jid = Jabber::JID.new('user#localhost')
cl = Jabber::Client.new(jid)
cl.connect
cl.auth('123456')
#online_users = [] #online users queue
roster = Jabber::Roster::Helper.new(cl)
mainthread = Thread.current
roster.add_presence_callback { |item,oldpres,pres|
if item.online?
#online_users.push item
else
#online_users.delete_if {|x| x.jid == item.jid }
end
puts #online_users.inspect
puts "#{item.jid} - online: #{item.online?}"
}
cl.send(Jabber::Presence.new.set_show(:dnd))
t = Thread.new { sleep XMPP_REQUEST_TIMEOUT; mainthread.wakeup;}
Thread.stop
cl.close
So I need some synchronous code, or some way to execute this kind of code in controller method.
Thanks.

For this found another solution that help me:
I installed a mod_rest in ejabberd server. This module allow that you do HTTP request of terminal commands of ejabberdctl.
So it has "ejabberdctl connected_users", that return users online.
So in your model app using gem rest-client you can do something like it:
def online_users
response = RestClient.post('http://localhost:5280/rest', "connected_users")
response
end

You will be much happier in the long run if you use a library like Strophe.js to do this in the browser, talking to an XMPP server that has BOSH enabled. Snapshots of presence are never anywhere as interesting as you expect them to be, and you're going to have really bad authentication/authorization problems on the path down which you're heading.

Related

Allauth user_logged_in signal does not trigger in a TestCase

I'm using allauth for user management in my Django web app and I have functionality which finds session data stored when the user was not logged in and stores it when they next log in on the same session.
It is triggered on login via the standard allauth signal:
#receiver(user_logged_in)
def update_on_login(request, user, **kwargs):
print('Signal triggered')
# Do some stuff with session data here, e.g.:
for session_key in request.session.items():
...
This works perfectly when logging in via a web browser, but in TestCase functions the signal is not triggered at all when logging in with:
self.client = Client()
logged_in = self.client.login(username=self.username, password=self.password)
(I've also tried force_login and force_authenticate, but info on these indicates that they actually skip all real validation and just assume the user is logged in).
I think I've understood that client.login doesn't work because the test client doesn't really handle the request in the same way as a web browser would, but I can't say I really understand it.
I've also seen some indication that RequestFactory might be able to help in someway, but I haven't been able to trigger the signal with this either:
request = RequestFactory().post(reverse('account_login'), { 'username': self.username, 'password': self.password })
request.user = AnonymousUser()
response = login(request)
I've seen some comments about needing to call middleware as well, but pretty out of date and nothing clear enough for me to understand and try.
Any suggestions to point me in the right direction would be much appreciated.
Thanks in advance.

Docusign gem block request

I'm using the DocuSign ruby client (https://github.com/docusign/docusign-ruby-client) on ruby on rails to send a document via email to some clients, but when I deploy the project after 15 minutes the request between the application and DocuSign gets "paused". For some reason the gem creates the request but doesn't send it as you can see in the next image where I enable the debug in the gem:
In that point the log doesn't print any more after 15 minutes.
The code that send the message in my app is:
access_token = "xxxxxxx"
account_id = "xxxxxxxxx"
base_path = "xxxxxxxxxx"
envelope_args = {
signer_email: contact.email,
signer_name: contact.name,
template_id: document.docusign_id
}
#args = {
account_id: account_id,
base_path: base_path,
access_token: access_token,
envelope_args: envelope_args
}
envelope_args = #args[:envelope_args]
# 1. Create the envelope request object
envelope_definition = make_envelope(envelope_args)
# 2. Call Envelopes::create API method
# Exceptions will be caught by the calling function
envelope_api = create_envelope_api(#args)
envelope_api.create_envelope #args[:account_id], envelope_definition
I don't know what can I do.
Thank you
Your screenshot shows everything happening at 18:29:05 -- I don't understand the issue.
Also, have you tried install/using the RoR code example?
See if it has the same problem.
We looked for the issue in our code, but we saw that in the step which the request is send in the gem here always freezes. So we debugged there and we saw that curl was being used for ruby. At that point we saw that curl was trying to reconnect with Docusign but it wasn't success, so we found this issue in the version of curl that we had (https://github.com/curl/curl/issues/4499 )
To fix it we updated the version to the latest, and it fixed the issue.
Thanks for your answers.

How would I use rspec to test a method who's job is to post to a webhook?

I'm using rspec to test my application and I'm having a hard time figuring out how to test this. The Slack::Notifier's job is to send a post request to a webhook. Once I call this method in Rspec, I don't know how to see the response. Also, is it possible to match the format of this text to an expected text somewhere? My method is below. Thanks.
def notify
offset = 14400 #UTC to EST
notifier = Slack::Notifier.new Rails.application.secrets.slack_organization_name, Rails.application.secrets.slack_token, channel: "##{Rails.application.secrets.slack_channel}", username: Rails.application.secrets.slack_user_name
notifier.ping(":white_check_mark: *USAGE SUMMARY for #{(Time.now - offset).to_formatted_s(:long) }*")
count = 0
current_time = Time.now.to_i
live_response.each do |r|
if r["properties"]["time"] > ((current_time - offset) - 60) #&& r["properties"]["$initial_referring_domain"] == "capture.com"
notifier.ping("
*Name:* #{r["properties"]["$name"]}
*Event:* #{r["event"]}
*Keywords:* #{r["properties"]["keywords"]}
*Organization:* #{r["properties"]["organizationName"]}
*Email:* #{r["properties"]["$email"]}
*Time:* #{Time.at(r["properties"]["time"] + offset).utc.to_datetime.in_time_zone("Eastern Time (US & Canada)").to_formatted_s(:long_ordinal)}
*More Data:* #{ANALYTICS_URL}#{r["properties"]["distinct_id"]}
__________________________________________________
")
count +=1
end
end
notifier.ping("*There were #{count} events in this report.*")
end
Testing network communications (like API calls) is a tricky thing. Personally I would rely on programming by contract and testing in isolation - i.e. assume the external service is working fine and it responds positively for valid request.
Then you test your client code by checking that you are actually sending a valid request. For this stub the method where control exits your code into a library/system code. For example if you are making a HTTP GET request using a gem like HTTParty, then stub HTTParty.get i.e. HTTParty.stub(:get) and in that stub verify that correct parameters were sent.
On the other side of the spectrum you should also simulated both positive and negative responses from the web service and make sure your client code handles it in expected manner.
If you are making a real then you are introducing a lot of dependencies on your test : a test setup of external service, risk of network issues (timeout, n/w breakdown, etc) problems with external service and may be more.
If you yourself are writing that webservice too then test that one also in isolation, i.e by simulating valid and invalid inputs and making sure they are handled properly. This part is pretty much your controller specs or request specs.
Once again, this is my opinion. Suggestions to do this in a better way and constructive criticism on the shortcomings of this approach are definitely welcome.

Mechanize - Receiving Errno::EMFILE: Too many open files - socket(2) after a day

I'm running an application that uses mechanize to fetch some data every so often from an RSS feed.
It runs as a heroku worker and after a day or so I'm receiving the following error:
Errno::EMFILE: Too many open files - socket(2)
I wasn't able to find a "close" method within mechanize, is there anything special I need to be doing in order to close out my browser sessions?
Here is how I create the browser + read information:
def mechanize_browser
#mechanize_browser ||= begin
agent = Mechanize.new
agent.redirect_ok = true
agent.request_headers = {
'Accept-Encoding' => "gzip,deflate,sdch",
'Accept-Language' => "en-US,en;q=0.8",
}
agent
end
end
And actually fetching information:
response = mechanize_browser.get(url)
And then closing after the response:
def close_mechanize_browser
#mechanize_browser = nil
end
Thanks in advance!
Since you manually can't close each instance of Mechanize, you can try invoking Mechanize as a block. According to the docs:
After the block executes, the instance is cleaned up. This includes closing all open connections.
So, rather than abstracting Mechanize.new into a custom function, try running Mechanize via the start class method, which should automatically close all your connections upon completion of the request:
Mechanize.start do |m|
m.get("http://example.com")
end
I ran into this same issue. The Mechanize start example by #zeantsoi is the answer that I ended up following, but there is also a Mechanize.shutdown method if you want to do this manually without their block.
There is also an option that you can add a lambda on post_connect_hooks
Mechanize.new.post_connect_looks << lambda {|agent, url, response, response_body| agent.shutdown }

Session timeout using Clearance in a Rails app

I'm using Clearance for authentication in my Rails app. Does anyone know of a way to configure a session timeout? It's been logging me out within 5 minutes of when I login and I can't seem to locate anything that specifies how to set the timeout.
When you installed Clearance, I think it should have added a config/initializers/clearance.rb file. You can configure the session timeout in there through the use of the cookie_expiration config. From their docs, it can look like this:
#example
Clearance.configure do |config|
config.mailer_sender = 'me#example.com'
config.cookie_expiration = lambda { 2.weeks.from_now.utc }
config.password_strategy = MyPasswordStrategy
config.user_model = MyNamespace::MyUser
end
So, just give cookie expiration a lambda that returns a Time object that occurs sometime in the future.
Looking at the rdoc, there's a cookie_expiration method on the Clearance configuration class. Here it is -- look at the source for the method:
By default, it looks like it's 1 year:
def initialize
#mailer_sender = 'donotreply#example.com'
#cookie_expiration = lambda { 1.year.from_now.utc }
end
So I'd look at overriding that in the configuration.
http://rdoc.info:8080/github/thoughtbot/clearance/Clearance/Configuration#cookie_expiration-instance_method
If you're unable to find it, sometimes you can ask on the Thoughtbot IRC channel #thoughtbot on freenode. Sometimes the developers hang out there and they'll field questions.

Resources