Changeset 142
- Timestamp:
- 01/30/06 16:14:29 (3 years ago)
- Files:
-
- feedtree/trunk/publisher.conf (modified) (2 diffs)
- feedtree/trunk/src/net/feedtree/publisher/Publisher.java (modified) (18 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
feedtree/trunk/publisher.conf
r141 r142 14 14 15 15 # list of feed URLs to be fetched by the publisher & pushed to FeedTree 16 # (comma-separated, square-bracket-enclosed) 16 17 feeds = [ 17 "http://dsandler.org/wp/feed/atom/" 18 19 # just a simple feed URL 20 "http://dsandler.org/wp/feed/atom/", 21 22 # more complex example: a feed with a private fetch URL and a public URL 23 { url: "http://dsandler.org/wp/feed/rss2/", # private fetch URL 24 public_url: "http://dsandler.org/wp/feed/" # public URL 25 }, 18 26 ] 19 27 … … 55 63 node_port = 29691 56 64 57 # port for the Publisher web interface (currently unused)65 # port for the Publisher web interface 58 66 web_port = 8502 59 67 feedtree/trunk/src/net/feedtree/publisher/Publisher.java
r141 r142 20 20 /// \verbinclude publisher.conf 21 21 /// 22 /// At a minimum, \c feed_ urls must be specified for Publisher to operate.22 /// At a minimum, \c feed_feeds must be specified for Publisher to operate. 23 23 /// To generate signed entries, at least \c keystore must be specified. 24 24 … … 99 99 public static final String PROP_WEB_PORT = "web_port"; 100 100 101 /// JSON list (i.e. enclosed in square-brackets) of feed URLs 102 /// Example:101 /// JSON list (i.e. enclosed in square-brackets) of feed URLs or feed 102 /// structures. Example: 103 103 /// feeds = [ 104 104 /// "http://site.com/feed/atom/", 105 /// "http://site.com/feed/rss2/" 105 /// { 106 /// url: "file:///local/site/rss2.xml", 107 /// publicUrl: "http://site.com/feed/rss2/" 108 /// } 106 109 /// ] 107 110 public static final String PROP_FEEDS = "feeds"; 111 112 /// In a feed structure (element of <code>feeds</code>), the URL of the 113 /// feed to fetch and publish. Required in a feed structure. 114 public static final String PROP_FEEDS_FEED_URL = "url"; 115 116 /// In a feed structure (element of <code>feeds</code>), the public URL of 117 /// the feed (if different from the URL used for fetching). Optional. 118 public static final String PROP_FEEDS_FEED_PUBLIC_URL = "public_url"; 108 119 109 120 /// Filename of a local keystore (optional; required for signing entries) … … 134 145 protected PrivateKey m_key = null; 135 146 protected Signature m_signer = null; 136 protected String[] m_urls;147 protected Feed[] m_feeds; 137 148 138 149 protected Shelf m_storage; … … 165 176 public static String REPORT_URL = "http://stats.feedtree.net/report"; 166 177 178 protected static class Feed { 179 public String fetchUrl; 180 public String topic; 181 public Feed(String url) { this.fetchUrl = this.topic = url; } 182 public Feed(String fetchUrl, String topic) { 183 this.fetchUrl = fetchUrl; 184 this.topic = topic; 185 } 186 } 187 167 188 protected static int hashEntry(SyndEntry e) { 168 189 String desc = ""; … … 172 193 String title = e.getTitle(); 173 194 String link = e.getLink(); 195 String author = ""; 174 196 List authors = e.getAuthors(); 175 String author = (authors == null) ? "" : (String) authors.get(0); 197 if (authors != null) { 198 Object a0 = authors.get(0); 199 if (a0 != null) 200 author = a0.toString(); 201 } 176 202 Date date = e.getPublishedDate(); 177 203 … … 227 253 public void run() { 228 254 Logger.global.fine("### Refreshing all feeds"); 229 for (int i=0; i<m_ urls.length; i++) {255 for (int i=0; i<m_feeds.length; i++) { 230 256 boolean anyNew = false; 231 257 232 String feedUrl = m_urls[i]; 258 String feedTopic = m_feeds[i].topic; 259 String fetchUrl = m_feeds[i].fetchUrl; 233 260 234 261 /*the*/ long now = new Date().getTime(); 235 262 236 Logger.global.fine("### Refreshing: " + feedUrl); 263 Logger.global.fine("### Refreshing: " + feedTopic); 264 Logger.global.fine("### Fetching feed data from URL: " + fetchUrl); 237 265 LinkedList toPublish = new LinkedList(); 238 266 239 267 LinkedHashMap entriesSeen 240 = (LinkedHashMap)m_feedStorage.get(feed Url);268 = (LinkedHashMap)m_feedStorage.get(feedTopic); 241 269 if (entriesSeen == null) { 242 270 entriesSeen = new LinkedHashMap(); 243 m_feedStorage.put(feed Url, entriesSeen);271 m_feedStorage.put(feedTopic, entriesSeen); 244 272 } 245 273 … … 247 275 248 276 try { 249 URLConnection cx = new URL(fe edUrl).openConnection();277 URLConnection cx = new URL(fetchUrl).openConnection(); 250 278 cx.setRequestProperty("User-Agent", "FeedTreePublisher/1"); 251 279 feed = new SyndFeedInput().build(new XmlReader(cx)); 252 280 253 281 } catch (MalformedURLException exc) { 254 Logger.global.warning("error: invalid URL: " + fe edUrl);282 Logger.global.warning("error: invalid URL: " + fetchUrl); 255 283 } catch (IOException exc) { 256 Logger.global.warning("warning: couldn't read from URL: " + fe edUrl + " ("+exc+")");284 Logger.global.warning("warning: couldn't read from URL: " + fetchUrl + " ("+exc+")"); 257 285 } catch (ParsingFeedException exc) { 258 286 Logger.global.warning("warning: couldn't parse feed (line " 259 287 + exc.getLineNumber() + ", column " 260 288 + exc.getColumnNumber() + ") at URL: " 261 + fe edUrl + " ("+exc+" <- " + exc.getCause()289 + fetchUrl + " ("+exc+" <- " + exc.getCause() 262 290 + (exc.getCause() == null ? "" 263 291 : (" <- " + exc.getCause().getCause())) 264 292 + ")"); 265 293 } catch (FeedException exc) { 266 Logger.global.warning("warning: couldn't interpret feed at URL: " + fe edUrl + " ("+exc+")");294 Logger.global.warning("warning: couldn't interpret feed at URL: " + fetchUrl + " ("+exc+")"); 267 295 } 268 296 … … 303 331 304 332 IFeedUpdateEvent feedEvent = 305 generateSignedEvent(feed Url, feed, e);333 generateSignedEvent(feedTopic, feed, e); 306 334 307 335 toPublish.add(feedEvent); … … 320 348 321 349 if (!anyNew) { 322 Logger.global.fine("### Nothing new: " + feed Url);323 if ((now - getLastEventTimeForFeed(feed Url))350 Logger.global.fine("### Nothing new: " + feedTopic); 351 if ((now - getLastEventTimeForFeed(feedTopic)) 324 352 > m_heartbeatInterval) 325 353 { 326 Logger.global.fine("### Due for a heartbeat: " + feed Url);327 toPublish.add(generateSignedHeartbeat(feed Url));354 Logger.global.fine("### Due for a heartbeat: " + feedTopic); 355 toPublish.add(generateSignedHeartbeat(feedTopic)); 328 356 } 329 357 } … … 335 363 // have another full heartbeat interval before we have 336 364 // to send another HB. 337 setLastEventTimeForFeed(feed Url, now);365 setLastEventTimeForFeed(feedTopic, now); 338 366 339 367 for(Iterator eventIterator = toPublish.iterator(); … … 419 447 + getLocalNodeHandle().toString() 420 448 + "</title></head><body>"); 449 450 output.write("<h2>FeedTree Publisher: " 451 + getLocalNodeHandle().toString() 452 + "</h2>"); 421 453 422 454 // TODO: make this pretty 423 455 424 for(Iterator i = m_feedStorage.keySet().iterator(); i.hasNext();) 425 { 426 String feedUrl = (String)(i.next()); 427 Map entries = (Map)m_feedStorage.get(feedUrl); 428 output.write("<h3>Feed: <tt>" + feedUrl + "</tt></h3><ol>"); 456 for(int i=0; i<m_feeds.length; i++) { 457 Feed feed = m_feeds[i]; 458 String feedTopic = feed.topic; 459 output.write("<h3>Feed: <tt>" + feedTopic + "</tt></h3>"); 460 output.write("<p>Fetched from: <tt>" 461 + feed.fetchUrl + "</tt></p><ol>"); 462 Map entries = (Map)m_feedStorage.get(feedTopic); 429 463 if (entries != null) { 430 464 for (Iterator j = entries.values().iterator(); j.hasNext();) … … 436 470 + "</tt></small></li>"); 437 471 } 438 output.write("</ol>");439 472 } 473 output.write("</ol><hr/>"); 440 474 } 441 475 output.write("</body></html>"); … … 519 553 query.append("&published_feeds="); 520 554 521 for(int i=0; i<m_ urls.length; i++) {555 for(int i=0; i<m_feeds.length; i++) { 522 556 if (i>0) query.append("|"); 557 String topicUrl = m_feeds[i].topic; 523 558 try { 524 query.append(URLEncoder.encode( m_urls[i], "UTF-8"));559 query.append(URLEncoder.encode(topicUrl, "UTF-8")); 525 560 } catch (java.io.UnsupportedEncodingException exc) { 526 561 query.append(release); // sigh 527 562 } 528 563 query.append(','); 529 if (m_topics.containsKey( m_urls[i])) {530 Topic topic = (Topic) m_topics.get( m_urls[i]);564 if (m_topics.containsKey(topicUrl)) { 565 Topic topic = (Topic) m_topics.get(topicUrl); 531 566 query.append(topic.getId().toStringFull()); 532 567 } … … 597 632 598 633 public Publisher(Node node, int nodePort, int webPort, 599 String[] urls, PrivateKey key)634 Feed[] feeds, PrivateKey key) 600 635 { 601 636 super(node, nodePort); … … 636 671 m_nodePort = nodePort; m_webPort = webPort; 637 672 638 m_ urls = urls;673 m_feeds = feeds; 639 674 640 675 g_classLoader = this.getClass().getClassLoader(); … … 740 775 int webPort = g_config.optInt(PROP_WEB_PORT, 8500); 741 776 742 String[] urls = null;777 Feed[] feeds = null; 743 778 744 779 JSONArray urlList = g_config.optJSONArray(PROP_FEEDS); … … 749 784 } else { 750 785 int len = urlList.length(); 751 urls = new String[len];786 feeds = new Feed[len]; 752 787 try { 753 788 for (int i=0; i<len; i++) { 754 urls[i] = urlList.getString(i); 789 Object feedEntry = urlList.get(i); 790 if (feedEntry instanceof JSONObject) { 791 JSONObject fe = (JSONObject)feedEntry; 792 String url = fe.getString(PROP_FEEDS_FEED_URL); 793 feeds[i] = new Feed( 794 url, 795 fe.optString(PROP_FEEDS_FEED_PUBLIC_URL, url) 796 ); 797 } else { 798 feeds[i] = new Feed(feedEntry.toString()); 799 } 800 801 Logger.global.info("feed: " + feeds[i].topic); 802 Logger.global.info("feed's public URL: " + feeds[i].fetchUrl); 755 803 } 756 804 } catch (JSONException exc) { … … 795 843 Node node = Client.start_node(myPort, bs, bsPort, true); 796 844 797 Publisher appl = new Publisher(node, myPort, webPort, urls, privateKey);845 Publisher appl = new Publisher(node, myPort, webPort, feeds, privateKey); 798 846 } 799 847 }
