Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
349 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,45 @@ | |||
# Public distributable version of the client. | |||
|
|||
class Pebble | |||
|
|||
@run: (host, callback) -> | |||
pebble = new Pebble | |||
callback pebble | |||
pebble | |||
|
|||
constructor: (host) -> | |||
@events = {} | |||
@socket = io.connect host | |||
|
|||
on: (event, callback) -> | |||
@events[event]?= [] | |||
@events[event].push callback | |||
|
|||
watchAll: (channels...) -> | |||
for name, callback of channels | |||
@watch name, callback | |||
|
|||
watch: (channel, callback) -> | |||
@on channel, callback | |||
@loadHistoryFor @, channel, => | |||
@socket.on channel, (data) => @receive channel, data | |||
|
|||
trigger: (name, args...) -> | |||
callbacks = (@events[name] ?= []) | |||
for callback in callbacks | |||
callback.apply this, args | |||
|
|||
disconnected: (callback) -> @on 'disconnect', callback | |||
connected: (callback) -> @on 'connect', callback | |||
reconnected: (callback) -> @on 'reconnect', callback | |||
|
|||
receive: (channel, message) -> | |||
@trigger channel, message | |||
|
|||
loadHistory: (channel, callback) -> | |||
$.getJSON "/history/#{channel}", (data) => | |||
for message in data.reverse() | |||
@receive channel, message | |||
callback() if callback instanceof Function | |||
|
|||
window['Pebble'] = Pebble |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,59 @@ | |||
path = require 'path' | |||
sys = require 'sys' | |||
fs = require 'fs' | |||
io = require 'socket.io' | |||
redis = require('./pebble/redis').RedisWrapper | |||
web = require('./pebble/web').Web | |||
|
|||
class Pebble | |||
|
|||
constructor: (@config) -> | |||
@publishers = [] | |||
|
|||
# Adds a publisher to the current runner. | |||
add: (publisher) -> | |||
@publishers.push new publisher(@) | |||
|
|||
addFromRequire: (path) -> | |||
@add require(path).publisher | |||
|
|||
run: -> | |||
sys.puts "Starting pebble..." | |||
@redis = new redis @ | |||
@web = new web @ | |||
@broadcast = io.listen @web.app | |||
@broadcast.set 'log level', 0 | |||
for publisher in @publishers | |||
publisher.run() | |||
@web.run() | |||
|
|||
visitableURL: -> | |||
unless @_visitableURL? | |||
@_visitableURL = "http://#{@host()}" | |||
if @port()? | |||
@visitableURL += ":#{@port()}" | |||
@_visitableURL += "/" | |||
@_visitableURL | |||
|
|||
host: -> process.env.HOST or @get 'pebble.listen.host', 'localhost' | |||
port: -> process.env.PORT or @get 'pebble.listen.port', 3003 | |||
|
|||
get: (key, defaultValue) -> | |||
key_parts = key.split "." | |||
config = @config | |||
while key_parts.length > 0 | |||
part = key_parts.shift() | |||
config = config[part] | |||
return defaultValue unless config? | |||
config | |||
|
|||
|
|||
@run: (config_path, callback) -> | |||
config = JSON.parse fs.readFileSync(config_path) | |||
runner = new @(config) | |||
callback runner if callback instanceof Function | |||
runner.run() | |||
runner | |||
|
|||
Pebble.Base = require("./pebble/base").Base | |||
module.exports = Pebble |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,32 @@ | |||
sys = require 'sys' | |||
|
|||
class Base | |||
|
|||
name: "unknown" | |||
|
|||
constructor: (@runner) -> | |||
@configNamespace?= @name | |||
@namespace?= @name | |||
|
|||
isEnabled: -> @runner.get('pebble.enabled', []).indexOf(@name) > -1 | |||
|
|||
run: -> | |||
if @isEnabled() | |||
sys.puts "Starting publisher: #{@name}" | |||
@setup() | |||
|
|||
get: (key, defaultValue) -> | |||
@runner.get "#{@configNamespace}.#{key}", defaultValue | |||
|
|||
config: -> @runner.get @configNamespace | |||
|
|||
emit: (key, message) -> | |||
if message? | |||
key = "#{@namespace}:#{key}" | |||
else | |||
message = key | |||
key = @namespace | |||
@runner.io.sockets.emit key, message | |||
@runner.redis.addHistory key, JSON.stringify(message) | |||
|
|||
exports.Base = Base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,25 @@ | |||
irc = require('irc') | |||
Base = require('./base').Base | |||
|
|||
class IRC extends Base | |||
|
|||
name: "irc" | |||
|
|||
setup: -> | |||
@channels = @get('channels') | |||
@client = new irc.Client @get('server'), @get('user'), | |||
channels: @channels | |||
@setupListeners() | |||
|
|||
listeningTo: (channel) -> | |||
@channels.indexOf(channel) > -1 | |||
|
|||
setupListeners: -> | |||
@client.addListener 'message', (from, to, message) => | |||
if @listeningTo to | |||
@emit 'message', | |||
message: message | |||
channel: to, | |||
user: from | |||
|
|||
exports.publisher = IRC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,65 @@ | |||
redis = require 'redis' | |||
sys = require 'sys' | |||
|
|||
class RedisWrapper | |||
|
|||
constructor: (@runner) -> | |||
@host = process.env.REDIS_HOST || @runner.get 'redis.host', 'localhost' | |||
@port = process.env.REDIS_PORT || @runner.get 'redis.port', 6379 | |||
@password = process.env.REDIS_PASSWORD || @runner.get 'redis.password' | |||
@namespace = @runner.get 'redis.namespace', 'juggernaut' | |||
@maxHistory = @runner.get 'redis.maxHistory', 100 | |||
sys.puts "Connecting to Redis at #{@host}:#{@port}" | |||
@redis = redis.createClient @port, @host | |||
if @password? | |||
sys.puts 'Authing with redis password.' | |||
@redis.auth @password | |||
|
|||
publish: (key, message) -> | |||
if message? | |||
key = "#{@namespace}:#{key}" | |||
else | |||
message = key | |||
key = @namespace | |||
sys.puts "Publishing to #{key}" | |||
@redis.publish key, message | |||
|
|||
historyKeyFor: (channel) -> "#{@namespace}:history:#{channel}" | |||
|
|||
incrementCountFor: (key, offset) -> | |||
@redis.hincrby "#{@namespace}:#{key}", offset, 1 | |||
|
|||
getCounts: (key, maximum, callback) -> | |||
@redis.hgetall "#{@namespace}:#{key}", (err, results) => | |||
if err | |||
callback err | |||
else | |||
counts = [] | |||
for i in [0..(maximum - 1)] | |||
counts.push parseInt(results[i] || "0", 10) | |||
callback false, JSON.stringify counts | |||
|
|||
|
|||
addHistory: (channel, data) -> | |||
key = @historyKeyFor channel | |||
@redis.lpush key, data | |||
@redis.ltrim key, 0, @maxHistory - 1 | |||
|
|||
getHistory: (channel, callback) -> | |||
key = @historyKeyFor channel | |||
@redis.lrange key, 0, @maxHistory - 1, (err, result) => | |||
sys.puts "Getting history for #{key} - #{@maxHistory - 1}" | |||
if err | |||
sys.puts "Hadd error: #{err}" | |||
callback err | |||
else if not result | |||
callback true | |||
else | |||
callback false, "[#{result.join(", ")}]" | |||
|
|||
debugResponse: (err, result) -> | |||
sys.puts "Error: #{sys.inspect err}" | |||
sys.puts "Result: #{sys.inspect result}" | |||
|
|||
|
|||
exports.RedisWrapper = RedisWrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,36 @@ | |||
NTwitter = require 'ntwitter' | |||
Base = require('./base').Base | |||
sys = require 'sys' | |||
|
|||
class Twitter extends Base | |||
|
|||
name: "twitter" | |||
|
|||
setup: -> | |||
config = @config() | |||
@twitter = new NTwitter({ | |||
consumer_key: config.consumer.key | |||
consumer_secret: config.consumer.secret | |||
access_token_key: config.access_token.key | |||
access_token_secret: config.access_token.secret | |||
}) | |||
outer = @ | |||
@twitter.stream 'statuses/filter', track: config.track, (stream) => | |||
stream.on 'data', (tweet) => | |||
outer.emit 'tweet', outer.filtered tweet | |||
stream.on 'end', (resp) -> | |||
sys.puts "Twitter Connection ended, Status code was #{resp.statusCode}" | |||
stream.on 'error', (error) -> | |||
sys.puts "Error in Twitter: #{error.message}" | |||
|
|||
filtered: (tweet) -> | |||
text: tweet.text | |||
created_at: tweet.created_at | |||
id_str: tweet.id_str | |||
retweeted: tweet.retweeted | |||
user: | |||
name: tweet.user.name | |||
profile_image_url: tweet.user.profile_image_url | |||
screen_name: tweet.user.screen_name | |||
|
|||
exports.publisher = Twitter |
Oops, something went wrong.