Plugins

I decided that it would be a good idea to implement the handling of the feeds for Feedling as a plugin-based thigie. In an ideal world, this would mean that anyone could use a different handler for RSS feeds f they felt that mine sucked, or something. Equally, if people want to handle a different type of feed, they can implement that quite easily.

To create a plugin, you'll probably do best to use one of the existing plugins as a template, like RSSFeed, which can be downloaded from the Feedling SVN repository. All plugins must have a feed named 'Feed' which implements IFeed. Similarly, all plugins must have a unique namespace. There's probably a better way of doing this, but I can't be arsed to change it. The only library you'll need which defines IFeed and a custom class called FeedItem is the FeedHandlerPluginInterface.dll, which can also be found in the SVN repository.

Here's IFeed:

public interface IFeed { /// <summary> /// Called by the host when it has initialized the feed object and it's ready to begin listening. /// The host calls this method as a new thread. /// </summary> void Watch(object state); /// <summary> /// A list of the FeedItems that currently exist in the feed /// </summary> List<FeedItem> FeedItems { get; } /// <summary> /// The Uri that is regularly fetched by the feed /// </summary> Uri FeedUri { get; set; } /// <summary> /// The plugin name /// </summary> string PluginName { get; } /// <summary> /// The version of the plugin assembly /// </summary> string PluginVersion { get; } /// <summary> /// Copyright information about the plugin. /// </summary> string PluginCopyright { get; } /// <summary> /// A text description of the feed /// </summary> string Description { get; set; } /// <summary> /// A text title of the feed /// </summary> string Title { get; set; } /// <summary> /// The URL of a background image that the feed may specify /// </summary> Uri ImageUrl { get; set; } /// <summary> /// Called by the host when an instant update is required /// </summary> void Update(); /// <summary> /// This event is bound to by the host to be alerted when the plugin has finished updating the feed /// </summary> event EventHandler Updated; /// <summary> /// In minutes, how often the plugin should refresh /// </summary> int UpdateInterval { get; set; } /// <summary> /// The URL specified by the feed. This URL will be started when the user clicks a feed item /// </summary> Uri Url { get; set; } /// <summary> /// Checks if this feed is capable of handling the supplied xml document. /// </summary> /// <param name="xml">The XML returned by the FeedURI</param> /// <returns>True if this plugin should handle this type of feed</returns> bool CanHandle(IXPathNavigable xml); /// <summary> /// Supplies a new instance of the plugin when requested by the host /// </summary> /// <param name="uri">The URI of the feed</param> /// <returns>An IFeed which will regularly update and fetch feed items</returns> IFeed Factory(Uri uri); /// <summary> /// Supplies a new instance of the plugin when requested by the host /// </summary> /// <param name="uri">The URI of the feed</param> /// <param name="authtype">The authentication type used by the feed as specified in FeedAuthTypes</param> /// <param name="username">The authentication username</param> /// <param name="password">The authentication password</param> /// <returns>An IFeed which will regularly update and fetch feed items</returns> IFeed Factory(Uri uri, FeedAuthTypes authtype, string username, string password); }

It's reasonably simple.

For each plugin, Feedling will initiate a new plugin object. However, this object will never be used for fetching feeds. If the user adds a new feed, Feedling will fetch the XML for that feed and ask each plugin if they can handle it using CanHandle. If it finds a plugin that can, it calls the Factory method to generate a new plugin object and passes it the feed URL. The plugin should then populate the FeedItems list and refresh itself every so often, letting Feedling know when it's done so.