Skip to content

Commit

Permalink
ArchiveBot spike.
Browse files Browse the repository at this point in the history
  • Loading branch information
hannahwhy committed Sep 6, 2013
0 parents commit 8ce9860
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 0 deletions.
9 changes: 9 additions & 0 deletions Gemfile
@@ -0,0 +1,9 @@
source "https://rubygems.org"

gem 'capybara'
gem 'cinch', :git => 'https://github.com/cinchrb/cinch.git'
gem 'poltergeist'
gem 'redis-namespace'
gem 'sidekiq'
gem 'trollop'
gem 'uuidtools'
60 changes: 60 additions & 0 deletions Gemfile.lock
@@ -0,0 +1,60 @@
GIT
remote: https://github.com/cinchrb/cinch.git
revision: a78bfad4adea7498fcfefc2f1acf84d5e70bcb9c
specs:
cinch (2.0.9)

GEM
remote: https://rubygems.org/
specs:
capybara (2.1.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
celluloid (0.15.0)
timers (~> 1.1.0)
cliver (0.2.1)
connection_pool (1.1.0)
json (1.8.0)
mime-types (1.25)
mini_portile (0.5.1)
multi_json (1.7.9)
nokogiri (1.6.0)
mini_portile (~> 0.5.0)
poltergeist (1.4.1)
capybara (~> 2.1.0)
cliver (~> 0.2.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
rack (1.5.2)
rack-test (0.6.2)
rack (>= 1.0)
redis (3.0.4)
redis-namespace (1.3.1)
redis (~> 3.0.0)
sidekiq (2.14.0)
celluloid (>= 0.14.1)
connection_pool (>= 1.0.0)
json
redis (>= 3.0.4)
redis-namespace
timers (1.1.0)
trollop (2.0)
uuidtools (2.1.4)
websocket-driver (0.2.3)
xpath (2.0.0)
nokogiri (~> 1.3)

PLATFORMS
ruby

DEPENDENCIES
capybara
cinch!
poltergeist
redis-namespace
sidekiq
trollop
uuidtools
9 changes: 9 additions & 0 deletions archive.rb
@@ -0,0 +1,9 @@
require 'sidekiq'

class Archive
include Sidekiq::Worker

def perform(uri, ident)
# We do nothing for now!
end
end
42 changes: 42 additions & 0 deletions bot.rb
@@ -0,0 +1,42 @@
require 'cinch'
require 'redis-namespace'
require 'trollop'
require 'uri'

require File.expand_path('../brain', __FILE__)

opts = Trollop.options do
opt :server, 'IRC server, expressed as a URI (irc://SERVER:PORT or //SERVER:PORT)', :type => String
opt :nick, 'Nick to use', :default => 'ArchiveBot'
opt :channels, 'Comma-separated list of channels', :type => String
opt :schemes, 'Comma-separated list of acceptable URI schemes', :default => 'http,https'
opt :redis, 'Redis server for job tracking', :default => 'redis://localhost:6379'
opt :redis_namespace, 'Redis namespace for job tracking', :default => 'archivebot'
end

%w(server nick channels).each do |opt|
Trollop.die "#{opt} is required" unless opts[opt.to_sym]
end

schemes = opts[:schemes].split(',').map(&:strip)
channels = opts[:channels].split(',').map(&:strip)
uri = URI.parse(opts[:server])
rconn = Redis.new(:url => opts[:redis])
redis = Redis::Namespace.new(opts[:redis_namespace], :redis => rconn)

bot = Cinch::Bot.new do
configure do |c|
c.server = uri.host
c.port = uri.port
c.nick = opts[:nick]
c.channels = channels
end

brain = Brain.new(redis, schemes)

on :message, /\A\!archive (.+)\Z/ do |m, param|
brain.request_archive(m, param)
end
end

bot.start
50 changes: 50 additions & 0 deletions brain.rb
@@ -0,0 +1,50 @@
require 'uri'

require File.expand_path('../archive', __FILE__)
require File.expand_path('../job_tracking', __FILE__)

class Brain
include JobTracking

attr_reader :redis
attr_reader :schemes

def initialize(redis, schemes)
@redis = redis
@schemes = schemes
end

def request_archive(m, param)
# Do we have a valid URI?
begin
uri = URI.parse(param).normalize
rescue URI::InvalidURIError => e
reply m, "Sorry, that doesn't look like a URL to me."
return
end

# Is the URI in our list of recognized schemes?
if !schemes.include?(uri.scheme)
reply m, "Sorry, I can only handle #{schemes.join(', ')}."
return
end

# Is the job already known?
ident = job_ident(uri)
if has_job?(ident, redis)
reply m, "That URL is already being processed. Use !status #{ident} for updates."
return
end

# OK, add the job and queue it up.
add_job(ident, redis)
Archive.perform_async(uri, ident)
reply m, "Archiving #{uri.to_s}; use !status #{ident} for updates."
end

private

def reply(m, *args)
m.reply "#{m.user.nick}: #{args.join(' ')}"
end
end
20 changes: 20 additions & 0 deletions job_tracking.rb
@@ -0,0 +1,20 @@
require 'uuidtools'

module JobTracking
ARCHIVEBOT_V0_NAMESPACE = UUIDTools::UUID.parse('82244de1-c354-4c89-bf2b-f153ce23af43')

def job_ident(uri)
uuid = UUIDTools::UUID.sha1_create(ARCHIVEBOT_V0_NAMESPACE, uri.to_s)

# shorten it up a bit
uuid.to_i.to_s(36)
end

def has_job?(ident, redis)
redis.sismember('jobs', ident)
end

def add_job(ident, redis)
redis.sadd('jobs', ident)
end
end

0 comments on commit 8ce9860

Please sign in to comment.