Skip to content

Instantly share code, notes, and snippets.

@jbarrett
Created August 24, 2012 14:05
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jbarrett/3450944 to your computer and use it in GitHub Desktop.
FUSE Module to read/mount a RSS feed
#!/usr/bin/env perl
# rssfs.pl
use strict;
use warnings;
use Date::Parse;
use Fuse;
use HTML::FormatText::WithLinks;
use HTML::Strip;
use POSIX qw(ENOENT EISDIR EINVAL O_WRONLY);
use XML::FeedPP;
my ( $source, $mount ) = @ARGV if @ARGV;
( $source && $mount )
or die "Usage: ", $0, " http://rss-source/ mount-point/", "\n";
my %files;
sub populate {
my $feed = XML::FeedPP->new($source);
my $format = HTML::FormatText::WithLinks->new();
my $strip = HTML::Strip->new();
my $filename;
my $content;
my $feeddate = str2time( $feed->pubDate() ) || time;
undef %files;
%files = (
'update' => { type => 0100, mode => 0644, ctime => $feeddate, content => "" },
'.' => { type => 0040, mode => 0755, ctime => $feeddate },
'..' => {}
);
foreach my $item ( $feed->get_item() ) {
( $filename = $strip->parse( $item->title() ) ) =~ s#[/]#-#g;
$content = $format->parse( $item->description() );
$content .= "Link: " . $item->link() . "\n";
if ( $item->author() ) {
$filename .= " (" . $item->author() . ")";
}
$files{ $filename . '.txt' } = {
type => 0100,
mode => 0644,
ctime => str2time( $item->pubDate() ),
content => $content
};
}
}
sub path_to_ref {
my $path = shift;
$path =~ s#^/##;
$path = '.' unless length($path);
return ( \%{$files{$path}} );
}
sub rss_getdir {
return ( keys %files, 0 );
}
sub rss_getattr {
my $path = path_to_ref(shift);
return ( -ENOENT() ) unless $path;
my $context = Fuse::fuse_get_context();
my $size = length( $path->{content} ) || 0;
my $mode = ( $path->{type} << 9 ) + $path->{mode};
my $uid = $context->{uid};
my $gid = $context->{gid};
my $atime = my $ctime = my $mtime = $path->{ctime};
my ( $dev, $ino, $rdev, $blocks, $nlink, $blksize ) = ( 0, 0, 0, 1, 1, 1024 );
return ( $dev, $ino, $mode, $nlink, $uid, $gid, $rdev,
$size, $atime, $mtime, $ctime, $blksize, $blocks );
}
sub rss_open {
my ($path_txt, $flags) = @_;
if ($path_txt eq '/update' && $flags & O_WRONLY) {
populate();
return 0;
}
my $path = path_to_ref(shift);
return -ENOENT() unless $path;
return -EISDIR() if $path->{type} & 0040;
open my $fh, "<", \$path->{content};
binmode $fh;
return 0, $fh;
}
sub rss_read {
my ( $path, $bytes, $offset, $fh ) = @_;
my $buffer;
my $status = read( $fh, $buffer, $bytes, $offset );
if ( $status && $status > 0 ) {
return $buffer;
}
elsif ( $status && $status == 0 ) {
return $status;
}
return -EINVAL();
}
sub rss_release {
my ( $path, $flags, $fh ) = @_;
close($fh) if $fh;
return(0);
}
populate();
fork and exit;
Fuse::main(
mountpoint => $mount,
getdir => \&rss_getdir,
getattr => \&rss_getattr,
open => \&rss_open,
read => \&rss_read,
release => \&rss_release,
utime => sub { return 0; },
threaded => 0
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment