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
8 changed files
with
1,245 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# node webfinger | ||
|
||
An asynchronous webfinger client for [node](http://nodejs.org/). It returns an [XRD](http://hueniverse.com/2009/11/xrd-alignment-with-link-syntax/) object, given an email address. | ||
|
||
## Usage | ||
|
||
var wf = new webfinger.WebFingerClient(); | ||
var userUri = "foo@example.com"; | ||
var fingerPromise = wf.finger(userUri); | ||
fingerPromise.addCallback(function(xrdObj) { | ||
// Do something with the user's xrd object | ||
} | ||
|
||
## Example app | ||
|
||
From the top level directory of this project, run | ||
|
||
$ node webfinger.js <username>@gmail.com | ||
|
||
and the application will output the latest google public Buzz entry from that user. | ||
|
||
## TODO | ||
|
||
Fix up the XRD and Atom parsers. Currently doesn't work on Yahoo's XRD, for example. | ||
Error handling. |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
var sys = require('sys'), | ||
fs = require('fs'), | ||
sax = require("./sax"), | ||
path = require("path"), | ||
http = require("http"), | ||
events = require("events"), | ||
url = require("url"); | ||
|
||
/** | ||
* Crude sax-based Atom feed parser. | ||
* Use like so: | ||
* | ||
* var atomParser = new atom.AtomParser(false) //not strict | ||
* var parserPromise = atomParser.parse(feedXmlText); | ||
* parserPromise.addCallback(function(atomFeed) { | ||
* sys.puts(atomFeed.entries[0].title); | ||
* }); | ||
* | ||
* The feed object itself is structured like this: | ||
* | ||
* feed | ||
* links[] | ||
* entries[] | ||
* title | ||
* summary | ||
* published | ||
* updated | ||
* id | ||
* links[] | ||
* author | ||
* name | ||
* uri | ||
* content | ||
* | ||
* Not entirely sure it needs to return a promise, the way | ||
* it's written it doesn't do any buffering. That may come | ||
* later though. | ||
* | ||
* Sean McCullough banksean@gmail.com | ||
* | ||
*/ | ||
|
||
var AtomFeed = function() { | ||
this.links = []; | ||
this.entries = []; | ||
this.title = ""; | ||
this.updated = ""; | ||
}; | ||
|
||
var Entry = function() { | ||
this.links = []; | ||
this.title = ""; | ||
this.updated = ""; | ||
this.published = ""; | ||
this.summary = ""; | ||
this.content = ""; | ||
} | ||
|
||
AtomFeed.prototype.getLinksByRel = function(rel) { | ||
var ret = []; | ||
for (var i=0; i<this.links.length; i++) { | ||
var link = this.links[i]; | ||
if (link.rel == rel) { | ||
ret.push(link); | ||
} | ||
} | ||
return ret; | ||
} | ||
|
||
var AtomParser = function(strict) { | ||
this.strict = false; | ||
}; | ||
|
||
exports.AtomParser = AtomParser; | ||
|
||
AtomParser.prototype.parse = function(data) { | ||
var parser = sax.parser(this.strict); | ||
var promise = new events.Promise(); | ||
var feed = new AtomFeed(); | ||
var currentEntry = null; | ||
var currentNodeName = ""; | ||
var skippingActivity = false; // Sorry, actionstrea.ms :) | ||
|
||
parser.onerror = function (e) { | ||
promise.emitError(e); | ||
}; | ||
|
||
parser.ontext = function (t) { | ||
var el; | ||
if (currentEntry != null) { | ||
el = currentEntry; | ||
} else { | ||
el = feed; | ||
} | ||
if (currentNodeName == "TITLE") { | ||
el.title += t; | ||
} else if (currentNodeName == "SUMMARY") { | ||
el.summary += t; | ||
} else if (currentNodeName == "PUBLISHED") { | ||
el.published += t; | ||
} else if (currentNodeName == "UPDATED") { | ||
el.updated += t; | ||
} else if (currentNodeName == "ID") { | ||
el.id += t; | ||
} else if (currentNodeName == "CONTENT") { | ||
el.content += t; | ||
} | ||
}; | ||
|
||
parser.onopentag = function (node) { | ||
if (skippingActivity) { return; } | ||
|
||
if (node.name == "ENTRY") { | ||
currentEntry = new Entry(); | ||
feed.entries.push(currentEntry); | ||
} else if (node.name == "LINK") { | ||
var l = {}; | ||
for (var attrName in node.attributes) { | ||
l[attrName] = node.attributes[attrName]; | ||
} | ||
if (currentEntry == null) { | ||
// LINKs for the feed itself | ||
feed.links.push(l); | ||
} else { | ||
currentEntry.links.push(l); | ||
} | ||
} else if (node.name =="ACTIVITY:OBJECT") { | ||
skippingActivity = true; | ||
} | ||
currentNodeName = node.name; | ||
}; | ||
|
||
parser.onclosetag = function (name) { | ||
if (name == "ENTRY") { | ||
currentEntry = null; | ||
} else if (name =="ACTIVITY:OBJECT") { | ||
skippingActivity = false; | ||
} | ||
}; | ||
|
||
parser.onattribute = function (attr) { | ||
/* | ||
*/ | ||
}; | ||
|
||
parser.onend = function () { | ||
promise.emitSuccess(feed); | ||
}; | ||
|
||
parser.write(data).close(); | ||
return promise; | ||
}; |
Oops, something went wrong.