Skip to content

Commit b253e94

Browse files
committed
fuck a color history
0 parents  commit b253e94

15 files changed

Lines changed: 542 additions & 0 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

LICENSE.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2011 GitHub Inc.
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node_modules/coffee-script/bin/coffee bin/hubot

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
Hubot
2+
=====
3+
4+
This is a version of GitHub's Campfire bot, hubot. He's pretty cool.
5+
6+
This version is designed to be deployed on heroku.
7+
8+
9+
Deployment
10+
==========
11+
12+
% git clone https://github.com/github/hubot.git
13+
% cd hubot
14+
% heroku create --stack cedar
15+
% git push heroku master
16+
% heroku ps:scale web=1
17+
18+
Hubot needs four environmental variables set to run and to keep him
19+
running on heroku.
20+
21+
Campfire Variables
22+
------------------
23+
24+
Create a separate user for your bot and get their token from the web UI.
25+
26+
% heroku config:add HUBOT_CAMPFIRE_TOKEN="..."
27+
28+
Get the numeric ids of the rooms you want the bot to join, comma
29+
delimited.
30+
31+
% heroku config:add HUBOT_CAMPFIRE_ROOMS="42,1024"
32+
33+
Add the subdomain hubot should connect to. If you web URL looks like
34+
`http://mysubdomain.campfirenow.com` then you'd add it like this.
35+
36+
% heroku config:add HUBOT_CAMPFIRE_ACCOUNT="mysubdomain"
37+
38+
The Web Host
39+
------------
40+
In order to keep hubot running, he needs to trick heroku into thinking
41+
he's constantly getting web traffic. Hubot will automatically ping his
42+
HTTP endpoint if you set the `HUBOT_WEB_HOST` variable. You can get the
43+
web endpoint by running `heroku info` and getting the hostname from the
44+
Web URL. Be sure to remove the `http://` prefix from it.
45+
46+
% heroku config:add HUBOT_WEB_HOST="galaxy324.herokuapp.com"
47+
48+
49+
Restart the bot
50+
---------------
51+
You may want to get comfortable with `heroku logs` and `heroku restart`
52+
if you're having issues.
53+
54+
Local Testing
55+
=============
56+
57+
It's easy to test scripts locally with the shell:
58+
59+
% bin/hubot -a stdio
60+

bin/hubot

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env coffee
2+
##
3+
# hubot [options]
4+
#
5+
# Launch an interactive hubot
6+
#
7+
require.paths.unshift __dirname + "/../node_modules"
8+
require.paths.unshift __dirname + "/../src"
9+
10+
Path = require 'path'
11+
HTTP = require 'http'
12+
OptParse = require 'optparse'
13+
PortNumber = parseInt(process.env.PORT) || 8080
14+
15+
Switches = [
16+
[ "-h", "--help", "Display the help information"],
17+
[ "-a", "--adapter ADAPTER", "The Adapter to use"]
18+
]
19+
20+
Options =
21+
adapter: "campfire"
22+
23+
Parser = new OptParse.OptionParser(Switches)
24+
Parser.banner = "Usage hubot [options]"
25+
26+
Parser.on "adapter", (opt, value) ->
27+
Options.adapter = value
28+
29+
Parser.parse process.ARGV
30+
31+
Options.adapter
32+
33+
switch Options.adapter
34+
when "stdio"
35+
Hubot = require("hubot/shell").Shell
36+
when "campfire"
37+
Hubot = require("hubot/campfire").Campfire
38+
39+
robot = new Hubot Path.resolve(__dirname, "..", "src", "hubot", "scripts")
40+
robot.run()
41+
42+
server = HTTP.createServer( (req, res) ->
43+
res.writeHead 200, {'Content-Type': 'text/plain'}
44+
res.end 'Hello from Hubot\n'
45+
).listen PortNumber
46+
47+
setInterval(( ->
48+
httpOpts =
49+
host: process.env.HUBOT_WEB_HOST
50+
51+
HTTP.get( httpOpts, (res) ->
52+
console.log "Got response: #{res}" unless res.statusCode == 200
53+
).on 'error', (e) ->
54+
console.log "Got error: #{e.message}"
55+
), 60000)
56+
57+
# vim:ft=coffee

package.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "hubot",
3+
"version": "0.1.0",
4+
"author": "GitHub Inc.",
5+
"keywords": "github hubot campfire bot",
6+
"description": "A simple helpful Robot for your Company",
7+
"licenses": [{
8+
"type": "MIT",
9+
"url": "http://github.com/github/hubot/raw/master/LICENSE"
10+
}],
11+
12+
"repository" : {
13+
"type" : "git",
14+
"url" : "http://github.com/github/hubot.git"
15+
},
16+
17+
"dependencies": {
18+
"coffee-script": "1.1.1",
19+
"optparse": "1.0.1"
20+
},
21+
22+
"directories": {
23+
"lib": "./src"
24+
},
25+
"main": "./src/hubot",
26+
"bin": {
27+
"hubot": "./bin/hubot"
28+
}
29+
}

src/hubot/campfire.coffee

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
Robot = require "robot"
2+
HTTPS = require "https"
3+
EventEmitter = require("events").EventEmitter
4+
5+
class Campfire extends Robot
6+
send: (user, strings...) ->
7+
strings.forEach (str) =>
8+
@bot.Room(user.room).speak str, (err, data) ->
9+
console.log "#{user}: #{str}"
10+
11+
reply: (user, strings...) ->
12+
strings.forEach (str) =>
13+
@send user, "#{user.name}: #{str}"
14+
15+
run: ->
16+
self = @
17+
options =
18+
token: process.env.HUBOT_CAMPFIRE_TOKEN
19+
rooms: process.env.HUBOT_CAMPFIRE_ROOMS
20+
account: process.env.HUBOT_CAMPFIRE_ACCOUNT
21+
22+
console.log options
23+
bot = new CampfireStreaming(options)
24+
console.log bot
25+
26+
bot.on "TextMessage", (id, created, room, user, body) ->
27+
if body.match new RegExp "^#{bot.info.name}", "i"
28+
bot.User user, (err, userData) ->
29+
self.receive(
30+
text: body
31+
user: { id: user, name: userData.user.name, room: room }
32+
)
33+
34+
bot.Me (err, data) ->
35+
console.log data
36+
bot.info = data.user
37+
bot.rooms.forEach (room_id) ->
38+
bot.Room(room_id).join (err, callback) ->
39+
bot.Room(room_id).listen()
40+
41+
@bot = bot
42+
43+
exports.Campfire = Campfire
44+
45+
class CampfireStreaming extends EventEmitter
46+
constructor: (options) ->
47+
@token = options.token
48+
@rooms = options.rooms.split(",")
49+
@account = options.account
50+
@domain = @account + ".campfirenow.com"
51+
@authorization = "Basic " + new Buffer("#{@token}:x").toString("base64")
52+
53+
Rooms: (callback) ->
54+
@get "/rooms", callback
55+
56+
User: (id, callback) ->
57+
@get "/users/#{id}", callback
58+
59+
Me: (callback) ->
60+
@get "/users/me", callback
61+
62+
Room: (id) ->
63+
self = @
64+
65+
show: (callback) ->
66+
self.post "/room/#{id}", "", callback
67+
join: (callback) ->
68+
self.post "/room/#{id}/join", "", callback
69+
leave: (callback) ->
70+
self.post "/room/#{id}/leave", "", callback
71+
lock: (callback) ->
72+
self.post "/room/#{id}/lock", "", callback
73+
unlock: (callback) ->
74+
self.post "/room/#{id}/unlock", "", callback
75+
76+
# say things to this channel on behalf of the token user
77+
paste: (text, callback) ->
78+
@message text, "PasteMessage", callback
79+
sound: (text, callback) ->
80+
@message text, "SoundMessage", callback
81+
speak: (text, callback) ->
82+
@message text, "TextMessage", callback
83+
message: (text, type, callback) ->
84+
body = { message: { "body":text, "type":type } }
85+
self.post "/room/#{id}/speak", body, callback
86+
87+
# listen for activity in channels
88+
listen: ->
89+
headers =
90+
"Host" : "streaming.campfirenow.com",
91+
"Authorization" : self.authorization
92+
93+
options =
94+
"host" : "streaming.campfirenow.com"
95+
"port" : 443
96+
"path" : "/room/#{id}/live.json"
97+
"method" : "GET"
98+
"headers": headers
99+
100+
request = HTTPS.request options, (response) ->
101+
response.setEncoding("utf8")
102+
response.on "data", (chunk) ->
103+
if chunk.match(/^\S+/)
104+
console.log "#{new Date}: Received #{id} \"#{chunk}\""
105+
try
106+
chunk.split("\r").forEach (part) ->
107+
data = JSON.parse part
108+
109+
self.emit data.type, data.id, data.created_at, data.room_id, data.user_id, data.body
110+
data
111+
112+
response.on "end", ->
113+
console.log "Streaming Connection closed. :("
114+
process.exit(1)
115+
116+
response.on "error", (err) ->
117+
console.log err
118+
request.end()
119+
request.on "error", (err) ->
120+
console.log err
121+
console.log err.stack
122+
123+
# Convenience HTTP Methods for posting on behalf of the token"d user
124+
get: (path, callback) ->
125+
@request "GET", path, null, callback
126+
127+
post: (path, body, callback) ->
128+
@request "POST", path, body, callback
129+
130+
request: (method, path, body, callback) ->
131+
headers =
132+
"Authorization" : @authorization
133+
"Host" : @domain
134+
"Content-Type" : "application/json"
135+
136+
options =
137+
"host" : @domain
138+
"port" : 443
139+
"path" : path
140+
"method" : method
141+
"headers": headers
142+
143+
if method == "POST"
144+
if typeof(body) != "string"
145+
body = JSON.stringify body
146+
options.headers["Content-Length"] = body.length
147+
148+
request = HTTPS.request options, (response) ->
149+
data = ""
150+
response.on "data", (chunk) ->
151+
data += chunk
152+
response.on "end", ->
153+
try
154+
callback null, JSON.parse(data)
155+
catch err
156+
callback null, data || { }
157+
response.on "error", (err) ->
158+
callback err, { }
159+
160+
if method == "POST"
161+
request.end(body)
162+
else
163+
request.end()
164+
request.on "error", (err) ->
165+
console.log err
166+
console.log err.stack
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module.exports = (robot) ->
2+
robot.hear /(image|img)( me)? (.*)/i, (response) ->
3+
imagery = response.match[3]
4+
imgurl = 'http://ajax.googleapis.com/ajax/services/search/images?' +
5+
'v=1.0&rsz=8&q=' +escape(imagery)
6+
7+
response.fetch imgurl, (res) ->
8+
images = JSON.parse(res.body)
9+
images = images.responseData.results
10+
image = response.random images
11+
12+
response.send image.unescapedUrl + "#.png"
13+
14+
robot.hear /animate me (.*)/i, (response) ->
15+
imagery = response.match[1]
16+
imgurl = 'http://ajax.googleapis.com/ajax/services/search/images?' +
17+
'v=1.0&rsz=8&as_filetype=gif&q=animted%20' +escape(imagery)
18+
19+
response.fetch imgurl, (res) ->
20+
images = JSON.parse(res.body)
21+
images = images.responseData.results
22+
image = response.random images
23+
24+
response.send image.unescapedUrl + "#.png"

src/hubot/scripts/maps.coffee

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports = (robot) ->
2+
robot.hear /(?:(satellite|terrain|hybrid)[- ])?map me (.+)/i, (response) ->
3+
mapType = response.match[1] || "roadmap"
4+
location = response.match[2]
5+
url = "http://maps.google.com/maps/api/staticmap?markers=" +
6+
escape(location) +
7+
"&size=400x400&maptype=" +
8+
mapType +
9+
"&sensor=false" +
10+
"&format=png" # So campfire knows it's an image
11+
12+
response.send url
13+

src/hubot/scripts/mustache.coffee

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module.exports = (robot) ->
2+
robot.hear /(?:mo?u)?sta(?:s|c)he?(?: me)? (.*)/i, (response) ->
3+
imagery = response.match[1]
4+
mustachify = "http://mustachify.me/?src="
5+
imageUrl = 'http://ajax.googleapis.com/ajax/services/search/images?' +
6+
'v=1.0&rsz=8&q=' +escape(imagery)
7+
8+
if imagery.match /^https?:\/\//i
9+
response.send "#{mustachify}#{imagery}"
10+
else
11+
response.fetch imageUrl, (res) ->
12+
images = JSON.parse(res.body)
13+
images = images.responseData.results
14+
image = response.random images
15+
16+
response.send "#{mustachify}#{image.unescapedUrl}#.png"

0 commit comments

Comments
 (0)