Monday, April 04, 2011 at 1:06 AM.

river2Suite.readFeed

on readFeed (url) {
	<<Changes
		<<3/31/11; 4:41:09 PM by DW
			<<Add eTag support.
				<<http://www.pocketsoap.com/weblog/stories/2002/05/0015.html
		<<3/31/11; 1:07:14 PM by DW
			<<Read the text of the feed here, pass it to xml.rss.getFeedItems, but only if the text changed.
		<<5/17/10; 5:06:47 PM by DW
			<<If the feed is not enabled, don't read it. Makes it easy to stop feeds that are updating more than is reasonable.
		<<12/24/09; 8:43:34 AM by DW
			<<Hook into cloudpipe on new items if the server is enabled.
		<<9/15/09; 11:24:46 AM by DW
			<<Read all the photos in a newly-subscribed-to photo feed.
		<<9/10/09; 11:27:04 AM by DW
			<<If the items don't have guids, synthesize them by mashing up title, pubdate and link.
		<<9/6/09; 3:46:55 PM by DW
			<<When we're booting up for the first time, let all news items through. Don't want an empty news page!
		<<9/1/09; 11:24:53 AM by DW
			<<If the number of errors exceeds the max, unsub from the feed.
		<<8/30/09; 5:25:22 PM by DW
			<<Track read errors.
		<<6/16/09; 10:50:14 AM by DW
			<<Created. 
	local (adrdata = river2Suite.init (), items, feedinfo, adritem, now = clock.now (), startticks = clock.ticks (), flphotofeed, headers);
	local (adrfeed = river2suite.initfeed (url), urllist, timeout = 60 * adrdata^.prefs.ctSecsTimeout, flfeedtextchanged);
	if not adrfeed^.prefs.enabled { //5/17/10 by DW
		return (false)};
	try {
		bundle { //set urllist
			try {
				urllist = string.urlsplit (url)}
			else {
				urllist = string.urlsplit (url + "/")}};
		bundle { //set up headers table
			new (tabletype, @headers);
			if defined (adrfeed^.data.eTag) {
				headers.["If-None-Match"] = adrfeed^.data.eTag}};
		local (s = tcp.httpClient (server:urllist [2], path:urllist [3], flMessages:false, ctFollowRedirects:5, timeOutTicks:timeout, adrHdrTable:@headers));
		local (code = string.nthField (s, ' ', 2));
		s = string.httpResultSplit (s, @headers); //; scratchpad.headers = headers
		if defined (headers.eTag) {
			adrfeed^.data.eTag = headers.eTag};
		bundle { //set flfeedtextchanged
			if code == "304" {
				flfeedtextchanged = false;
				adrfeed^.stats.ct304s++;
				adrdata^.stats.ct304s++}
			else {
				if s == adrfeed^.data.feedtext {
					flfeedtextchanged = false}
				else {
					flfeedtextchanged = true}}};
		if flfeedtextchanged {
			xml.rss.getFeedItems (url, @items, @adrfeed^.feedinfo);
			adrfeed^.data.feedtext = s;
			adrfeed^.stats.ctFeedTextChanges++;
			adrfeed^.stats.whenLastFeedTextChange = now}}
	else {
		local (errorstring = "Error reading <a href=\"" + url + "\">feed</a>: " + tryerror);
		adrfeed^.stats.ctReadErrors++;
		if ++adrfeed^.stats.ctConsecutiveReadErrors >= adrdata^.prefs.maxConsecutiveFeedErrors {
			river2Suite.unsubscribeFeed (adrfeed);
			log2.add (river2Info.name, "Unsub", errorstring, startticks)}
		else {
			adrfeed^.stats.whenLastReadError = now;
			adrfeed^.stats.lastReadError = tryerror;
			log2.add (river2Info.name, "Read", errorstring, startticks)};
		return (false)};
	bundle { //debugging
		if adrdata^.prefs.flDebug {
			local (adrfeeds = @system.temp.river2.debug.feeds);
			if not defined (adrfeeds^) {
				new (tabletype, adrfeeds)};
			local (adrfeed = @adrfeeds^.[url]);
			if not defined (adrfeed^) {
				new (tabletype, adrfeed)};
			adrfeed^.items = items}};
	adrfeed^.stats.ctReads++;
	adrfeed^.stats.whenLastRead = now;
	if flfeedtextchanged {
		adrfeed^.stats.ctItemsLastRead = sizeof (items);
		bundle { //set flphotofeed, 9/15/09 by DW
			flphotofeed = false;
			if defined (adrfeed^.feedinfo.category) {
				flphotofeed = string.lower (adrfeed^.feedinfo.category) == "photos"}};
		<<scratchpad.items = items
		for adritem in @items {
			local (guid);
			bundle { //set guid
				try {
					guid = xml.getvalue (adritem, "guid")}
				else {
					guid = ""; //synthesize the guid -- 9/10/09 by DW
					try {guid = guid + xml.getvalue (adritem, "pubDate")};
					try {guid = guid + xml.getvalue (adritem, "link")};
					try {guid = guid + xml.getvalue (adritem, "title")};
					if sizeof (guid) > 0 {
						guid = string.hashmd5 (guid)}}};
			if sizeof (guid) > 0 {
				local (adrhistory = @adrfeed^.history.[guid]);
				if not defined (adrhistory^) {
					if (adrfeed^.stats.ctReads > 1) or adrdata^.stats.flInstalling or flphotofeed {
						<<first time we read a feed none of the items are new, unless we're installing or it's a photo feed
						river2suite.newItem (adritem, adrfeed);
						if adrdata^.prefs.cloudPipeServer.enabled { //12/24/09 by DW
							river2Suite.cloudPipe.serverNewItem (url, adritem)}};
					adrhistory^ = now}}}};
	return (true)};
bundle { //test code
	readFeed ("http://scripting.com/rss.xml")}
	<<readFeed ("http://static.flickrfan.org/afp/rss.xml")



This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.