Skip to content

Instantly share code, notes, and snippets.

@botanicus
Created April 15, 2011 10:39
Show Gist options
  • Select an option

  • Save botanicus/921506 to your computer and use it in GitHub Desktop.

Select an option

Save botanicus/921506 to your computer and use it in GitHub Desktop.
.rvmrc
*.log
*.pid
#!/usr/bin/env ruby
# encoding: utf-8
require "bundler"
Bundler.setup
require "redis"
redis = Redis.new
redis.keys("*").each do |key|
puts "Deleting record with key '#{key}' ..."
redis.del(key)
end
# encoding: utf-8
source :rubygems
gem "redis"
gem "em-websocket"
gem "eventmachine", "0.12.10" #, "1.0.0.beta.3"
gem "amq-protocol", :git => "git://github.com/ruby-amqp/amq-protocol.git", :branch => "master"
gem "amq-client", :git => "git://github.com/ruby-amqp/amq-client.git", :branch => "master"
GIT
remote: git://github.com/ruby-amqp/amq-client.git
revision: 787643de901955cf8d137d1057a5e416547dbaae
branch: master
specs:
amq-client (0.5.0.pre)
amq-protocol
GIT
remote: git://github.com/ruby-amqp/amq-protocol.git
revision: e669f5d8ec7e59da63aa8cde49c9f1862b7a5c4b
branch: master
specs:
amq-protocol (0.0.1)
GEM
remote: http://rubygems.org/
specs:
addressable (2.2.5)
em-websocket (0.2.1)
addressable (>= 2.1.1)
eventmachine (>= 0.12.9)
eventmachine (0.12.10)
redis (2.2.0)
PLATFORMS
ruby
DEPENDENCIES
amq-client!
amq-protocol!
em-websocket
eventmachine (= 0.12.10)
redis
#!/usr/bin/env ruby
# encoding: utf-8
require "bundler"
Bundler.setup
require "json"
require "amq/client"
require "amq/client/adapters/event_machine"
require "amq/client/queue"
require "em-websocket"
require_relative "subscription"
# Helpers.
def run(&block)
if ARGV.include?("--daemon")
logfile = File.join(Dir.pwd, "github.log")
pidfile = File.join(Dir.pwd, "github.pid")
pid = fork do
STDERR.reopen(logfile)
STDOUT.reopen(logfile)
Dir.chdir("/")
trap("TERM") { EM.stop }
EM.run(&block)
end
puts "Starting daemon with PID #{pid} ..."
File.open(pidfile, "w") do |file|
file.puts(pid)
end
else
EM.run(&block)
end
end
# Main loop.
run do
EM::WebSocket.start(host: "0.0.0.0", port: 8080) do |socket|
AMQ::Client::EventMachineClient.connect do |client|
channel = AMQ::Client::Channel.new(client, 1)
channel.open do |method|
Subscription.slugs.each do |slug|
queue = AMQ::Client::Queue.new(client, channel, slug)
queue.consume(true)
queue.on_delivery do |method, header, body|
data = JSON.parse(body)["payload"]
# 0) Debug.
puts "==> #{method.routing_key.inspect}"
puts data.inspect
puts
# 1) Store to Redis.
Subscription.get(queue.name) << data
# 2) Notify clients via websockets.
socket.send({slug => data}.to_json)
end
end
end
end
end
end
#!/bin/sh
ROOT=/github/backend
PIDFILE=/github/backend/github.pid
start () {
$ROOT/github.rb --daemon
}
stop () {
kill $(cat $PIDFILE)
}
case "$1" in
start|"")
start ;;
restart)
stop && start ;;
stop)
stop ;;
*)
echo "Usage: $0 [start|restart|stop]" >&2
exit 1
;;
esac
#!/usr/bin/env ruby
# encoding: utf-8
require "bundler"
Bundler.setup
require_relative "subscription"
# All commits to Ruby AMQP repos.
Subscription.create("Ruby AMQP", "ruby-amqp", "github.commit.ruby-amqp.#")
# All my commits to any repos.
Subscription.create("Jakub Stastny's Commits", "botanicus", "#[email protected]")
#!/usr/bin/env ruby
# encoding: utf-8
require "bundler"
Bundler.setup
require_relative "subscription"
redis = Subscription.redis
slugs = Subscription.slugs
slugs.each do |slug|
user = redis.hgetall(slug)
data = redis.lrange(user["pattern"], 0, -1)
puts "#{slug} #{user.inspect}"
puts "=> #{data}"
puts
end
# encoding: utf-8
require "redis"
require "json"
# There are two types of routing keys, github.commit and github.push:
# [email protected]
# github.push.ruby-amqp.amqp.master
class Subscription
# @return [Redis] Cached redis instance.
def self.redis
@redis ||= Redis.new
end
def self.slugs
self.redis.lrange("slugs", 0, -1)
end
# @return [Subscription] New Subscription instance with commits.
def self.get(slug)
key = self.redis.hget(slug, "pattern")
data = self.redis.lrange(key, 0, -1)
data.map! { |json| JSON.parse(json) }
self.new(key, data)
end
# {slug => {name: name, pattern: pattern}}
def self.create(name, slug, pattern)
self.redis.multi do
@redis.rpush("slugs", slug)
@redis.hset(slug, "name", name)
@redis.hset(slug, "pattern", pattern)
end
self.amqp_subscribe(slug, pattern)
end
# TODO: refactor
def self.amqp_subscribe(queue_name, routing_pattern)
require "amq/client"
require "amq/client/adapters/event_machine"
require "amq/client/queue"
EM.run do
AMQ::Client::EventMachineClient.connect do |client|
channel = AMQ::Client::Channel.new(client, 1)
channel.open do |method|
queue = AMQ::Client::Queue.new(client, channel, queue_name)
queue.declare(false, true) do |method|
queue.bind("github", routing_pattern) do |method|
EM.stop
end
end
end
end
end
end
attr_reader :data
def initialize(key, data = Array.new)
@key, @data = key, data
end
def push(commit)
index = self.class.redis.rpush(@key, commit.to_json)
self.class.redis.ltrim(@key, 0, 20 - 2)
return commit
end
alias_method :<<, :push
def destroy
self.class.redis.del(@key)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment