Friday: a feed reader for castaways
News feeds! Where would we be without them? Living in caves, caves with celebrity baby portraits scrawled onto the walls. Feeds liberate the internet’s constant readers from the sad spectacle of gyrating bodies advertising low-rate mortgages, which is known as the world wide web.
Failure to communicate
Besides restoring an ounce of decency to on-line news reading, feeds enable much greater efficiency than the raw web by demarcating individual stories, so that the reader software can track read stories for the user. In theory, you never have to see the same dumb story twice. If you skim hundreds of stories a week and do not want to miss anything or waste your time, using a feed reader is more than worth the hassle.
There is only one problem: most of us kids these days are using more than one computer! (Except for the all-eggs-in-one-notebook crowd, and they really should get out more.) Using more than one computer breaks read status tracking, whether you read with separate readers or fall back to slurping the web on satellite machines. If you feed-read at work you’re lost on the weekend or when traveling, and inundated with stale news when you return. The happy vs. hassle seesaw flops in the wrong direction, and this is why 0.0% of the world actually uses desktop feed readers.
The web thinks it can solve this problem, like always. A web application acts as your feed reader, maintaining read status on Google or Blogline’s servers. This works well enough for a great number of people, but if you’ve ever used a desktop feed reader the web readers feel like clunk. Keyboard navigation is crucial for reading, but Javascript apps can’t reliably trap the best keys (cursors and space) across all browsers. So it becomes an exercise in mousing like the web in general, and who knows what hideous animated nonsense will be fed into the unprotected browser from the feed or the reader app itself. You can keep it, masses!
The best solution to the problem came a hundred years ago when NewsGator started to offer free subscription and read status synchronization across feed reader instances, applications, and even platforms. They bought NetNewsWire and have been giving it away for free. It is basically crazy not to use their software and services, unless you’re on a platform that lacks a compatible reader like Ubuntu. Then it’s kind of a major bummer that your new toy cuts you off from the stream of news that sustains your intellectual life! NewsGator is not building a Linux-compatible reader (they mostly seem to buy such things) and none of the Linux readers are working on integration with NewsGator, an imposing job to be sure.
So, project!
NewsGator’s ambitious synchronization actually makes the task of writing a compatible reader much easier. Whereas a traditional reader needs a persistent data model and user interface to support adding and organizing subscriptions, one that works through managed synchronization can leave that task up to other software. It only needs to know how to fetch unread stories and update their read status.
Among the NewsGator APIs is a REST one, which is an acronym meaning “let’s just do this with HTTP and try not to make everything needlessly painful.” Supposing you already had an HTTP interface you liked, and also a platform and environment for making fun desktop software, the path to writing this application would be pretty straightforward.
(It was.)
Say hello to Friday, a feed reader for eccentrics who like words. You can download a runnable jar for any platform, or a Mac application bundle containing that jar and with a hawt icns for the dock. (Runnable jars compressed by ProGuard are like Java Web Start without the wrist slitting and long downloads.) To run Friday you’ll need Java 1.5+ and a NewsGator account.
Fill the account with interesting feeds, either on NewGator’s site or with a compatible client like NetNewsWire, then open Friday and log in. (Name and password optionally save in Friday.properties
file of the working directory.) Cursor left and right to move through stories, up and down to scroll by page, spacebar to mark as read and enter to opens in your default web browser. It’s awesomer than it sounds. (Processing!) In fact, you might stop using your regular desktop feed reader even on platforms it supports, because Friday is more fun. Or maybe that attachment only develops if you develop Friday.
By the way, Friday is written in the complex, disappointing language known Scala, and not any of those fast and easy ‘type? shmype!’ languages that people are always using to write their own jaunty feed reading apps in their spare time for their personal use.
Actors are tougher than they sound and easier than they look
One thing that was new in Friday, for this coder, was using Actors. It’s bean real fun, guys, hearing about how easy that concurrency library was for the past year when we could not wrap our heads around it to save our lives! Turns out though you just have to know 90% of the Scala language, and then the Actors library is easy. So if you’re still suspicious about ‘currying’ and partial functions make you want to partially throw up, don’t worry about fully understanding Actors. That’s probably why they’re in the back of the book. But they are really super when you are ready to use them.
At Friday’s core is the beating heart of Processing, which will hit the draw method as fast as it can up to the maximum framerate you set, if any. So that is your main thread, and Actors are the perfect tool for doing work asynchronous to drawing. Since this is a network application, that is obligatory. Take a look:
def draw() {
if (applet.frame.isVisible)
writer !? Draw
}
This draw loop sends a synchronous Draw
message to writer
. It doesn’t run in parallel since we want the draw commands to execute before the method terminates, as normal for Processing. If that were its only entry point writer
wouldn’t need to be an Actor, but it also receives messages from an Actor that runs asynchronously. Actors will only process one message at a time, so writer
can safely update its local variable without worrying about stepping on its own toes.
val writer: Actor = actor {
var program = Program(Nil)
act_loop {
react {
case Draw =>
val last_moving = program.moving
background(0xFF999999)
program = program.draw
if (!(last_moving || program.moving)) {
noLoop()
}
reply(None)
case p: Program =>
program = p
loop()
...
Whoa, name collisions galore! We had to make use of one of Scala’s complex features to rename Actor.loop
to act_loop
, since loop
is itself a pretty important method in Processing.
import scala.actors.Actor.{loop => act_loop, link => act_link, _}
How complex and quite scary! You can do something like that or you can just not use these awesome libraries that happen to conflict, take your pick. The methods loop()
and noLoop()
turn off and on the hungry draw loop in Processing’s main thread. That might seem like a gratuitous optimization, but it is the difference between Friday using a responsible amount of processor time when idle versus it turning your laptop into a space heater. The reply(..)
call is only necessary for messages that are sent synchronously.
It’s a two-day week here
Awesomely, Processing’s text wrapping is already fixed in 1.0 core, so now Friday has regular margins.
That is all for now! There is enough material in Friday for a half dozen posts, and the software is not finished either. Mainly, it needs Spde to offer better long text rendering than what comes with Processing (something that wraps before instead of after hitting the margin, etc) to advance. But still it’s kind of sweet already, no? You can hack away on Friday inside Spde (torrents), and clone from:
git clone git://technically.us/git/Friday
But please don’t add gyrating bodies to any Friday fork.
Codercomments
Very cool … thanks for the writeup and example code to play with.
I’m a Google Reader type of guy myself, but always appreciate new scala code in the wild that I can learn from.
Thanks, -steve
I was going to talk some trash about Google Reader specifically, but then I looked at it last night (fact checking!) and it has improved considerably since I first saw it. It’s not bad, for a web-based feed reader.
Death to the Google Reader trash-talkers!! :-)
Seriously, I use Google Reader to manage hundreds of feeds with ~150-200 new items per day. I almost never have a problem with it. I have used desktop clients (including NewsGator), but they just aren’t as efficient. I’ll grant you that Reader used to suck some serious a**, but since the redesign (two+ years ago), it’s been very very good.
With that said, I wish you the best of luck with Friday! One thing you might want to consider in addition to NewsGator synchronization is Google Reader sync. It does have an API AFAIK that you can use to do similar things behind the scenes. Considering that more people use Reader these days than all the other RSS aggregators put together (source Feedburner), it might be a bigger draw.
I haven’t used their windows client, FeedDemon, enough to know if it’s comparable to NNW. And while you’ve made an informed decision, I’m sure that most people haven’t gone as far as to set up synchronization (if they’ve tried a desktop reader at all), leaving them with the false impression that the killer feature of universal read status is unique to web-based readers. Well, anyway, it’s good to know that Google has an API as well in case NewsGator folds, which wouldn’t be for a lack of good ideas or products (just a lack of Google’s market-crushing name, I cynically insist). Barring that sad possibility I’ll continue to stick with NewsGator’s news software and services, which happen to be the best. ;)
Add a comment