Skip to content

Instantly share code, notes, and snippets.

@rkh
Created March 16, 2012 10:35
Show Gist options
  • Save rkh/2049493 to your computer and use it in GitHub Desktop.
Save rkh/2049493 to your computer and use it in GitHub Desktop.
# coding: binary
# IRC <-> Campfire bridge, set IRC password to SUBDOMAIN:TOKEN and connect to localhost:6667
# Remove special chars/spaces from channel names (ie "Foo Bar" becomes #FooBar). Only tested with LimeChat.
# gem install excon && gem install yajl-ruby -v "< 2.0"
%w[socket thread uri excon yajl yajl/http_stream].each { |lib| require lib }
Thread.abort_on_exception = true
[:INT, :TERM].each { |sig| trap(sig) { exit } }
server = TCPServer.new('127.0.0.1', 6667)
loop do
Thread.new(server.accept) do |irc|
out = Queue.new
writer = Thread.new { loop { irc << out.pop.to_s << "\r\n" } }
token = subdomain = url = nick = nil
rooms, users, streams = {}, {}, {}
add_user = proc { |data| data['name'].split(' ').first.tap { |n| users[n] = data['id'] } }
http = proc { |v,r,a={}| Yajl.load Excon.public_send(v, "https://#{token}:x@#{subdomain}.campfirenow.com/#{r}.json", a).body }
get, post = http.curry[:get], http.curry[:post]
until irc.closed? or irc.eof?
rest, last = irc.gets.chop.split(":", 2)
command, *args = rest.split(" ")
args << last
case command
when "USER", "PONG"
when "PASS"
subdomain, token = args
get['rooms']['rooms'].each { |d| rooms["##{d['name'].gsub(/\W/, '')}"] = d['id'] }
nick = add_user[get['users/me']['user']]
out << ":localhost 001 #{nick} :Welcome to the #{subdomain} IRC Network #{nick}\r\n:localhost 002 #{nick} :Your host is localhost"
out << ":localhost 003 #{nick} :This server was created #{Time.now}\r\n:localhost 004 #{nick} :CampIRC 0.0.1 hello fake"
when "NICK"
out << ":#{args.first} NICK #{nick}"
when "PRIVMSG"
room_id, body = rooms[args[0]], Yajl.dump('message' => {'body' => args[1].gsub(/\x01(ACTION)?/, '')})
post["room/#{room_id}/speak", :body => body, :headers => {"Content-Type" => "application/json"}] if room_id
when "JOIN"
channel = args.first
if room_id = rooms[channel]
post["room/#{room_id}/join"]
data = get["room/#{room_id}"]['room']
nicks = data['users'].map { |u| add_user[u] }
out << ":#{nick} JOIN #{channel}\r\n:localhost 332 #{nick} #{channel} :#{data['topic']}\r\n:localhost 333 #{nick} #{channel} #{nick} #{Time.now.to_i}"
out << ":localhost 353 #{nick} @ #{channel} :#{nicks.join " "}\r\n:localhost 366 #{nick} @ #{channel} :End of /NAMES list"
streams[channel] = Thread.new do
Yajl::HttpStream.get URI.parse("http://#{token}:x@streaming.campfirenow.com//room/#{room_id}/live.json") do |msg|
next unless channel = rooms.key(msg['room_id'])
user = users.key(msg['user_id']) || add_user[get["users/#{msg['user_id']}"]] if msg['user_id']
case msg['type'].downcase
when 'timestampmessage'
when 'textmessage', 'pastemessage', 'tweetmessage', 'uploadmessage' then out << ":#{user} #{user == nick ? "NOTICE" : "PRIVMSG"} #{channel} :#{msg['body']}"
when 'kickmessage', 'leavemessage' then out << ":#{user} PART #{channel} :#{msg['type']}"
when 'entermessage' then out << ":#{user} JOIN #{channel}"
when "topicchangemessage" then out << ":#{user} TOPIC #{channel} :#{msg['body']}"
when "soundmessage" then out << ":#{user} PRIVMSG #{channel} :\x01ACTION plays #{msg['body']}\x01"
else puts "unsupported message: #{msg.inspect}"
end
end
end
else
out << ":localhost 403 #{channel} :No such channel"
end
when "QUIT"
writer.kill
streams.each_value(&:kill)
irc.close
else
puts "unkown command #{command}"
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment