Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 20c50e94a44ff95fc1c72d4a0a08279b7b6cc5ca @mrduncan mrduncan committed Jan 20, 2011
Showing with 454 additions and 0 deletions.
  1. +20 −0 LICENSE
  2. +33 −0 README.md
  3. +10 −0 TODO.md
  4. +48 −0 lib/ranger/client.js
  5. +128 −0 lib/ranger/connection.js
  6. +13 −0 lib/ranger/index.js
  7. +38 −0 lib/ranger/message.js
  8. +140 −0 lib/ranger/room.js
  9. +24 −0 package.json
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Matt Duncan
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 README.md
@@ -0,0 +1,33 @@
+Ranger
+======
+
+Ranger is a [node.js](http://nodejs.org/) library for interacting with [Campfire](http://campfirenow.com/).
+
+Usage
+-----
+The following example gets an array of rooms which the user is present in and then plays the `vuvuzela` sound and says "vuvuzela time!" in the first one.
+
+ var client = require("ranger").createClient("account", "api-key");
+ client.presence(function (rooms) {
+ rooms[0].play("vuvuzela");
+ rooms[0].speak("vuvuzela time!");
+ });
+
+The createClient function takes two parameters:
+
+1. The account name, which is the subdomain of your account url. If your account url is `37signals.campfire.com` then your account name would be `37signals`.
+2. The api key of the user to connect as. You can get it from the "My info" link once logged into Campfire.
+
+Contributing
+------------
+
+1. [Fork](http://help.github.com/forking/) Ranger
+2. Create a topic branch - git checkout -b mybranch
+3. Push to your branch - git push origin mybranch
+4. Create a new pull request
+
+Author
+------
+Matt Duncan
+[mattduncan.org](http://mattduncan.org)
+[matt@mattduncan.org](mailto:matt@mattduncan.org)
10 TODO.md
@@ -0,0 +1,10 @@
+TODO
+====
+
+- Unstar messages
+- Streaming messages
+- File uploads
+- Uploaded file listings
+- Search
+- Message transcripts
+- Room creation (not documented but seems supported)
48 lib/ranger/client.js
@@ -0,0 +1,48 @@
+var Connection = require("./connection").Connection,
+ Room = require("./room").Room;
+
+/**
+ * A campfire client for a specific account.
+ * @constructor
+ * @param {string} account The name of the account to connect to.
+ * @param {string} token The api token to connect with.
+ */
+exports.Client = function (account, token) {
+ /**
+ * Convert the specified response data into an array of Rooms.
+ * @param {Object} data The server response data.
+ * @return {Array.<Room>} An array of Rooms.
+ */
+ function toRooms(data) {
+ var i, rooms;
+
+ rooms = [];
+ for (i = 0; i < data.rooms.length; i++) {
+ rooms.push(new Room(connection, data.rooms[i]));
+ }
+
+ return rooms;
+ }
+
+ var connection = new Connection(account, token);
+
+ /**
+ * Gets an array of all rooms.
+ * @param {function(Array.<Room>)} callback The callback to call with results.
+ */
+ this.rooms = function (callback) {
+ connection.get("/rooms.json", function (data) {
+ callback(toRooms(data));
+ });
+ };
+
+ /**
+ * Gets an array of all rooms which the api user is present in.
+ * @param {function(Array.<Room>)} callback The callback to call with results.
+ */
+ this.presence = function (callback) {
+ connection.get("/presence.json", function (data) {
+ callback(toRooms(data));
+ });
+ };
+};
128 lib/ranger/connection.js
@@ -0,0 +1,128 @@
+var http = require("http");
+
+/**
+ * Returns the base64 encoded string.
+ * @param {string} str The string to base64 encode.
+ * @return {string} The base64 encoded string.
+ */
+var base64Encode = function (str) {
+ var buffer = new Buffer(str, "utf8");
+ return buffer.toString("base64");
+};
+
+/**
+ * A connection to the campfire server.
+ * @constructor
+ * @param {string} account The name of the account to connect to.
+ * @param {string} token The api token to connect with.
+ */
+exports.Connection = function (account, token) {
+ var authorization = "Basic " + base64Encode(token + ":X");
+
+ /**
+ * Performs a request on the connection.
+ * @param {string} method The http request method.
+ * @param {string} path The path to request.
+ * @param {Object} body The object to send as the body of the request.
+ * @param {function()=} callback The callback to call when the request completes.
+ */
+ this.request = function (method, path, body, callback) {
+ var headers, jsonBody, client, request;
+
+ headers = {
+ "Authorization": authorization,
+ "Host": account + ".campfirenow.com",
+ "Content-Type": "application/json"
+ };
+
+ if (method === "POST" || method === "PUT" || method === "DELETE") {
+ if (body) {
+ jsonBody = JSON.stringify(body);
+ headers["Content-Length"] = jsonBody.length;
+ } else {
+ headers["Content-Length"] = 0;
+ }
+ }
+
+ client = http.createClient(443, headers.Host, true);
+ request = client.request(method, path, headers);
+ request.on("response", function (response) {
+ var data = "";
+
+ response.on("data", function (chunk) {
+ data += chunk;
+ });
+ response.on("end", function () {
+ var parsedObj;
+
+ if (callback) {
+ try {
+ parsedObj = JSON.parse(data);
+ } catch (err) {
+
+ }
+
+ if (parsedObj) {
+ callback(parsedObj);
+ } else {
+ callback();
+ }
+ }
+ });
+ });
+
+ if (jsonBody) {
+ request.write(jsonBody);
+ }
+
+ request.end();
+ };
+
+ /**
+ * Performs a get request on the specified path.
+ * @param {string} path The request path.
+ * @param {function()=} callback The function to call when the request completes.
+ */
+ this.get = function (path, callback) {
+ this.request("GET", path, null, callback);
+ };
+
+ /**
+ * Performs a post request on the specified path.
+ * @param {string} path The request path.
+ * @param {Object=} body The body of the request.
+ * @param {function()=} callback The function to call when the request completes.
+ */
+ this.post = function (path, body, callback) {
+ if (typeof body === "function") {
+ callback = body;
+ body = null;
+ }
+
+ this.request("POST", path, body, callback);
+ };
+
+ /**
+ * Performs a put request on the specified path.
+ * @param {string} path The request path.
+ * @param {Object=} body The body of the request.
+ * @param {function()=} callback The function to call when the request completes.
+ */
+ this.put = function (path, body, callback) {
+ if (typeof body === "function") {
+ callback = body;
+ body = null;
+ }
+
+ this.request("PUT", path, body, callback);
+ };
+
+ /**
+ * Performs a delete request on the specified path.
+ * @param {string} path The request path.
+ * @param {function()=} callback The function to call when the request completes.
+ */
+ this.del = function (path, callback) {
+ this.request("DELETE", path, null, callback);
+ };
+};
13 lib/ranger/index.js
@@ -0,0 +1,13 @@
+var Client = require("./client").Client;
+
+exports.version = "0.1.0";
+
+/**
+ * Returns a campfire client.
+ * @constructor
+ * @param {string} account The name of the account to connect to.
+ * @param {string} token The api token to connect with.
+ */
+exports.createClient = function (account, token) {
+ return new Client(account, token);
+};
38 lib/ranger/message.js
@@ -0,0 +1,38 @@
+/**
+ * A chat message.
+ * @constructor
+ * @param {Connection} connection A server connection.
+ * @param {Object} attrs The initial attributes of this message.
+ */
+exports.Message = function (connection, attrs) {
+ var self, urlFor, post;
+
+ self = this;
+ this.type = attrs.type;
+ this.id = attrs.id;
+ this.roomId = attrs.room_id;
+ this.body = attrs.body;
+ this.userId = attrs.user_id;
+ this.createdAt = new Date(attrs.created_at);
+
+ /**
+ * Returns the url for the specified action.
+ * @param {string} action The action to get the url for.
+ * @return {string} The url for the specified action.
+ */
+ urlFor = function (action) {
+ return "/messages/" + self.id + "/" + action + ".json";
+ };
+
+ post = function (action, body, callback) {
+ connection.post(urlFor(action), body, callback);
+ };
+
+ /**
+ * Highlights this message.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.star = function (callback) {
+ post("star", callback);
+ };
+};
140 lib/ranger/room.js
@@ -0,0 +1,140 @@
+var Message = require('./message.js').Message;
+
+/**
+ * A chat room.
+ * @constructor
+ * @param {Connection} connection A server connection.
+ * @param {Object} attrs The initial attributes of this room.
+ */
+exports.Room = function (connection, attrs) {
+ var self, urlFor, get, post, put, sendMessage;
+
+ self = this;
+ this.id = attrs.id;
+ this.name = attrs.name;
+ this.topic = attrs.topic;
+ this.membershipLimit = attrs.membership_limit;
+ this.locked = attrs.locked;
+ this.createdAt = new Date(attrs.created_at);
+ this.updatedAt = new Date(attrs.updated_at);
+
+ /**
+ * Returns the url for the specified action.
+ * @param {string} action The action to get the url for.
+ * @return {string} The url for the specified action.
+ */
+ urlFor = function (action) {
+ return "/room/" + self.id + "/" + action + ".json";
+ };
+
+ get = function (action, callback) {
+ connection.get(urlFor(action), callback);
+ };
+
+ post = function (action, body, callback) {
+ connection.post(urlFor(action), body, callback);
+ };
+
+ put = function (body, callback) {
+ connection.put("/room/" + self.id + ".json", body, callback);
+ };
+
+ /**
+ * Sends the specified message.
+ * @param {string} message The message to send.
+ * @param {string} type The type of message.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ sendMessage = function (message, type, callback) {
+ post("speak", {
+ message: {
+ body: message,
+ type: type
+ }
+ }, callback);
+ };
+
+ /**
+ * Sends the specified message.
+ * @param {string} message The message to send.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.speak = function (message, callback) {
+ sendMessage(message, "TextMessage", callback);
+ };
+
+ /**
+ * Sends the specified pre-formatted message.
+ * @param {string} message The message to send.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.paste = function (message, callback) {
+ sendMessage(message, "PasteMessage", callback);
+ };
+
+ /**
+ * Plays the sound with the specified name.
+ * @param {string} name The name of the sound to play.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.play = function (name, callback) {
+ sendMessage(name, "SoundMessage", callback);
+ };
+
+ /**
+ * Updates the specified room attributes.
+ * @param {Object} attributes The attributes to update.
+ * @param {function()=} callback The optional callback to call when comlete.
+ */
+ this.update = function (attributes, callback) {
+ // TODO: Update the name and topic of the room after complete
+ put({ room: attributes }, callback);
+ };
+
+ /**
+ * Join this room.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.join = function (callback) {
+ post("join", callback);
+ };
+
+ /**
+ * Leave this room.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.leave = function (callback) {
+ post("leave", callback);
+ };
+
+ /**
+ * Lock this room. You must be in a room to lock it.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.lock = function (callback) {
+ post("lock", callback);
+ };
+
+ /**
+ * Unlock this room.
+ * @param {function()=} callback The optional callback to call when complete.
+ */
+ this.unlock = function (callback) {
+ post("unlock", callback);
+ };
+
+ /**
+ * Gets up to 100 recent messages in the room.
+ * @param {function(Array.<Message>)} callback The callback to call with the array of messages.
+ */
+ this.recentMessages = function (callback) {
+ get("recent", function (data) {
+ var i, messages = [];
+ for (i = 0; i < data.messages.length; i++) {
+ messages.push(new Message(connection, data.messages[i]));
+ }
+
+ callback(messages);
+ });
+ };
+};
24 package.json
@@ -0,0 +1,24 @@
+{
+ "name": "ranger",
+ "description": "A node.js library for interacting with Campfire",
+ "keywords": [
+ "campfire",
+ "chat"
+ ],
+ "author": "Matt Duncan <matt@mattduncan.org> (http://mattduncan.org)",
+ "contributors": [],
+ "licenses": [
+ ""
+ ],
+ "dependencies": {},
+ "lib": "lib",
+ "main": "./lib/ranger",
+ "version": "0.1.0",
+ "engines": {
+ "node": ">= 0.2.0"
+ },
+ "homepage": "http://github.com/mrduncan/ranger",
+ "directories": {
+ "lib": "lib"
+ }
+}

0 comments on commit 20c50e9

Please sign in to comment.