patternrubyMajor
Chat bot for posting recent answers
Viewed 0 times
chatrecentanswerspostingbotfor
Problem
I am the half-robot side of syb0rg that will be posting the recent answers of Code Review to the CR Answers chatroom. Here is the list of review suggestions I would like, in order of preference:
For feature requests regarding the chat bot, please see this meta post.
Any and all reviews are acceptable however. Don't be too harsh please, this is one of my first times using Ruby.
```
ACCESS_TOKEN = ''
# get your access token here:
# https://stackexchange.com/oauth/dialog?client_id=2666&redirect_uri=http://keyboardfire.com/chatdump.html&scope=no_expiry
$root = 'http://stackexchange.com'
$chatroot = 'http://chat.stackexchange.com'
$room_number = 12723
site = 'codereview'
email = ''
password = ''
require 'rubygems'
require 'mechanize'
require 'json'
require 'net/http'
loop
{
begin
$agent = Mechanize.new
$agent.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
login_form = $agent.get('https://openid.stackexchange.com/account/login').forms.first
login_form.email = email
login_form.password = password
$agent.submit login_form, login_form.buttons.first
puts 'logged in with SE openid'
meta_login_form = $agent.get($root + '/users/login').forms.last
meta_login_form.openid_identifier = 'https://openid.stackexchange.com/'
$agent.submit meta_login_form, meta_login_form.buttons.last
puts 'logged in to root'
chat_login_form = $agent.get('http://stackexchange.com/users/chat-login').forms.last
$agent.submit chat_login_form, chat_login_form.buttons.last
puts 'logged in to chat'
$fkey = $agent.get($chatroot + '/chats/join/favorite').forms.last.fkey
puts 'found fkey'
def send_message text
loop
{
begin
resp = $agent.post("#{$chatroot}/chats/#{$room_number}/messages/new", [['text', text], ['fkey', $fkey]]).body
success = JSON.parse(resp)['id']
- Efficiency (with API requests, speed of login and posting answers, etc.)
- Security issues
- Best practices
For feature requests regarding the chat bot, please see this meta post.
Any and all reviews are acceptable however. Don't be too harsh please, this is one of my first times using Ruby.
```
ACCESS_TOKEN = ''
# get your access token here:
# https://stackexchange.com/oauth/dialog?client_id=2666&redirect_uri=http://keyboardfire.com/chatdump.html&scope=no_expiry
$root = 'http://stackexchange.com'
$chatroot = 'http://chat.stackexchange.com'
$room_number = 12723
site = 'codereview'
email = ''
password = ''
require 'rubygems'
require 'mechanize'
require 'json'
require 'net/http'
loop
{
begin
$agent = Mechanize.new
$agent.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
login_form = $agent.get('https://openid.stackexchange.com/account/login').forms.first
login_form.email = email
login_form.password = password
$agent.submit login_form, login_form.buttons.first
puts 'logged in with SE openid'
meta_login_form = $agent.get($root + '/users/login').forms.last
meta_login_form.openid_identifier = 'https://openid.stackexchange.com/'
$agent.submit meta_login_form, meta_login_form.buttons.last
puts 'logged in to root'
chat_login_form = $agent.get('http://stackexchange.com/users/chat-login').forms.last
$agent.submit chat_login_form, chat_login_form.buttons.last
puts 'logged in to chat'
$fkey = $agent.get($chatroot + '/chats/join/favorite').forms.last.fkey
puts 'found fkey'
def send_message text
loop
{
begin
resp = $agent.post("#{$chatroot}/chats/#{$room_number}/messages/new", [['text', text], ['fkey', $fkey]]).body
success = JSON.parse(resp)['id']
Solution
For starters, indent your code consistently — the standard in Ruby is two spaces. That includes indenting the contents of your
Normally, I don't like to make such a huge fuss about indentation, but in this case I think it's highly important, because:
An outline like this would be more idiomatic for Ruby:
begin-rescue-end blocks.Normally, I don't like to make such a huge fuss about indentation, but in this case I think it's highly important, because:
- Your program has a highly unusual outline (infinite loops and a function definition(!) inside an infinite loop)
- The stakes are high: if you misbehave, you could make a lot of people upset. Therefore, good software engineering practices should be used.
An outline like this would be more idiomatic for Ruby:
class AnswerBot
ROOT = 'http://stackexchange.com'
CHAT_ROOT = 'http://chat.stackexchange.com'
def initialize(options)
@agent = Mechanize.new
@options = options
end
def login
# Do stuff with @agent
login_form = $agent.get('https://openid.stackexchange.com/account/login').forms.first
login_form.email = @options[:email]
# ...
@fkey = @agent.get(CHAT_ROOT + '/chats/join/favorite').forms.last.fkey
end
def fetch_answers
# Make request to api.stackexchange.com
# ...
data['items'].each { |event| yield event }
return (data['backoff'] || 0).to_i
end
def send_message(text, retries=5, backoff=40)
# ...
end
end
bot = AnswerBot.new(:access_token => ...,
:room_number = 12723,
:site => 'codereview',
:email => ...,
:password => ...)
loop {
begin
bot.login
do
backoff = bot.fetch_answers do |event|
if ['answer_posted'].include?(event['event_type']) # e
puts "An error occurred."
p e
end
puts "Bot restarted."
}Code Snippets
class AnswerBot
ROOT = 'http://stackexchange.com'
CHAT_ROOT = 'http://chat.stackexchange.com'
def initialize(options)
@agent = Mechanize.new
@options = options
end
def login
# Do stuff with @agent
login_form = $agent.get('https://openid.stackexchange.com/account/login').forms.first
login_form.email = @options[:email]
# ...
@fkey = @agent.get(CHAT_ROOT + '/chats/join/favorite').forms.last.fkey
end
def fetch_answers
# Make request to api.stackexchange.com
# ...
data['items'].each { |event| yield event }
return (data['backoff'] || 0).to_i
end
def send_message(text, retries=5, backoff=40)
# ...
end
end
bot = AnswerBot.new(:access_token => ...,
:room_number = 12723,
:site => 'codereview',
:email => ...,
:password => ...)
loop {
begin
bot.login
do
backoff = bot.fetch_answers do |event|
if ['answer_posted'].include?(event['event_type']) # <-- Is that right?
bot.send_message(...)
end
end
while sleep(40 + backoff)
rescue => e
puts "An error occurred."
p e
end
puts "Bot restarted."
}Context
StackExchange Code Review Q#44511, answer score: 22
Revisions (0)
No revisions yet.