Intro
For months now I’ve had a tab open in my browser on my main computer - Reclaiming the Web with a Personal Reader. I’ve read the article a couple of times and really like the idea of using a personal and extendable feed reader.
Finally around a week ago I cloned the repo from GitHub to check it out. After a couple of tweaks to the Makefile to make it work with my laptops configuration I was up and running. Someone else noticed the thing with the port being in use so they submitted a pull request on the repo so I didn’t have to.
Overall, I really liked it! I did discover a small typo which kept feeds from syncing when you clicked the sync button. Though to be fair I shouldn’t have needed to click sync, I think it should have imported the initial feeds when I ran make feed-load
. But that’s just a little thing.
Python isn’t my strongest language so while I can follow along with the code OK I don’t feel like I can extend it as I see fit…
Desire to Extend
This led me to wanting to create my own version of the “personal feed reader”. Figuring this would be a good project for me to continue practicing my Go.
First, I made a list of packages that would get me to most of the basic functionality of the feed reader, leaving off Mastodon for now.
https://github.com/spf13/cobra
https://git.deanishe.net/deanishe/go-favicon
https://github.com/go-shiori/go-readability
https://github.com/go-co-op/gocron
https://github.com/mmcdole/gofeed
https://github.com/PuerkitoBio/goquery
I’m going to stick with using htmx and Bulma CSS as it’ll be a nice excuse to learn a bit about them.
To start my hacking away on the project I began with using the Cobra command line tools to stand up a basic app. From here I added skeleton commands, version
, feed-load
, serve
.
version
- doesn’t do much of anything at the moment.
feed-load
- reads a local CSV file and prints out the contents.
serve
- starts the HTTP server on 3000 and is slowly being extended to do other tasks.
What other tasks, you say?
While right now running serve
will start up the web server, begin the scheduler and schedule a dummy job that just says hello
. It will also load the feed CSV and do some parsing of the included feeds and then use readability on the feed links.
Databasing
My next step is to start working on the database. I need to do some research on properly doing migrations. The Go program/library migrate
looks like it may be useful in that regard. At first we’ll likely be modeling tables after what’s already presented to us as using the base feedi as a design building block.
0_create_table.down.sql
DROP TABLE IF EXISTS feeds;
0_create_table.up.sql
CREATE TABLE feeds (
id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
url VARCHAR,
type VARCHAR NOT NULL,
name VARCHAR,
icon_url VARCHAR,
created TIMESTAMP NOT NULL,
updated TIMESTAMP NOT NULL,
last_fetch TIMESTAMP,
raw_data VARCHAR,
folder VARCHAR,
etag VARCHAR,
modified_header VARCHAR,
filters VARCHAR,
mastodon_account_id INTEGER,
PRIMARY KEY (
id
),
UNIQUE (
user_id,
name
)
);
With the up/down files in ./migrations
I should be able to add a command migrate
and use the library to do the heavy lifting. I think, we’ll have to give it a whirl. Maybe I’ll write a small test project…
And my small test project was a success it seems. If you are interested here is the code.
package main
import (
"database/sql"
"fmt"
"log"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"
"github.com/golang-migrate/migrate/v4/source/file"
_ "github.com/mattn/go-sqlite3"
)
func main() {
// Connect to database
db, err := sql.Open("sqlite3", "feeds.db")
if err != nil {
log.Panic(err)
}
// defer close
defer db.Close()
dbDriver, err := sqlite3.WithInstance(db, &sqlite3.Config{})
if err != nil {
fmt.Printf("instance error: %v \n", err)
}
fileSource, err := (&file.File{}).Open("file://migrations")
if err != nil {
fmt.Printf("opening file error: %v \n", err)
}
m, err := migrate.NewWithInstance("file", fileSource, "feeds.db", dbDriver)
if err != nil {
fmt.Printf("migrate error: %v \n", err)
}
if err = m.Up(); err != nil {
fmt.Printf("migrate up error: %v \n", err)
}
fmt.Println("Migrate up done with success")
}
Enjoy this post? |
---|
How about buying me a coffee? |