refactor: tidy up app structure and entrypoint file
This commit is contained in:
parent
8dafeb7e17
commit
82f1c4bbb2
3 changed files with 114 additions and 93 deletions
|
@ -12,9 +12,15 @@ type Route struct {
|
||||||
Handler http.HandlerFunc
|
Handler http.HandlerFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
type API struct {
|
type BackgroundTask struct {
|
||||||
Routes []Route
|
Handler func()
|
||||||
StaticRoot string
|
Interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
Routes []Route
|
||||||
|
BackgroundTasks []BackgroundTask
|
||||||
|
StaticRoot string
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoggingMiddleware(f http.HandlerFunc) http.HandlerFunc {
|
func LoggingMiddleware(f http.HandlerFunc) http.HandlerFunc {
|
||||||
|
@ -25,7 +31,7 @@ func LoggingMiddleware(f http.HandlerFunc) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a API) Start(addr string) {
|
func (a App) Start(addr string) {
|
||||||
for _, route := range a.Routes {
|
for _, route := range a.Routes {
|
||||||
http.HandleFunc(route.Path, LoggingMiddleware(route.Handler))
|
http.HandleFunc(route.Path, LoggingMiddleware(route.Handler))
|
||||||
}
|
}
|
||||||
|
@ -34,9 +40,28 @@ func (a API) Start(addr string) {
|
||||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(a.StaticRoot))))
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(a.StaticRoot))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, task := range a.BackgroundTasks {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
task.Handler()
|
||||||
|
time.Sleep(task.Interval)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
http.ListenAndServe(addr, nil)
|
http.ListenAndServe(addr, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) AddRoute(path string, handler http.HandlerFunc) {
|
func (a *App) AddRoute(path string, handler http.HandlerFunc) {
|
||||||
a.Routes = append(a.Routes, Route{Path: path, Handler: handler})
|
a.Routes = append(a.Routes, Route{Path: path, Handler: handler})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewApp(routes map[string]http.HandlerFunc, backgroundTasks []BackgroundTask, staticRoot string) *App {
|
||||||
|
app := App{StaticRoot: staticRoot, BackgroundTasks: backgroundTasks}
|
||||||
|
|
||||||
|
for route, handler := range routes {
|
||||||
|
app.AddRoute(route, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &app
|
||||||
|
}
|
93
main.go
93
main.go
|
@ -1,86 +1,12 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"text/template"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var SharedCache *Datastore
|
var SharedCache *Datastore
|
||||||
|
|
||||||
type Link struct {
|
|
||||||
Url string `json:"url"`
|
|
||||||
PublishedDate string `json:"publishedDate"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Healthcheck route
|
|
||||||
//
|
|
||||||
// Confirms that the app is alive without guarantees
|
|
||||||
// about it being fully-functional.
|
|
||||||
func healthcheck(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// About page
|
|
||||||
//
|
|
||||||
// Static content for the about page.
|
|
||||||
func about(w http.ResponseWriter, r *http.Request) {
|
|
||||||
tmpl, _ := template.New("about.html.tmpl").ParseFiles("templates/about.html.tmpl")
|
|
||||||
tmpl.Execute(w, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feeds list
|
|
||||||
//
|
|
||||||
// Lists all feed elements in store.
|
|
||||||
func listContent(w http.ResponseWriter, r *http.Request) {
|
|
||||||
links := []Link{}
|
|
||||||
for _, feed := range SharedCache.List("feeds") {
|
|
||||||
var formattedItems []Link
|
|
||||||
json.Unmarshal([]byte(feed), &formattedItems)
|
|
||||||
links = append(links, formattedItems...)
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl, _ := template.New("index.html.tmpl").ParseFiles("templates/index.html.tmpl")
|
|
||||||
tmpl.Execute(w, links)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manage content
|
|
||||||
//
|
|
||||||
// Interface to add new feed subscriptions and get a list
|
|
||||||
// of current subs.
|
|
||||||
func manageContent(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method == "POST" {
|
|
||||||
r.ParseForm()
|
|
||||||
|
|
||||||
urlValue := r.PostFormValue("url")
|
|
||||||
|
|
||||||
if _, err := url.Parse(urlValue); err != nil {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cacheKey := fmt.Sprintf("feedurl:%s", urlValue)
|
|
||||||
SharedCache.Set(cacheKey, urlValue)
|
|
||||||
|
|
||||||
go fetchFeed(urlValue)
|
|
||||||
|
|
||||||
w.WriteHeader(201)
|
|
||||||
}
|
|
||||||
|
|
||||||
allFeeds := SharedCache.List("feedurl")
|
|
||||||
|
|
||||||
type ManageTmplData struct {
|
|
||||||
Feeds map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl, _ := template.New("manage.html.tmpl").ParseFiles("templates/manage.html.tmpl")
|
|
||||||
tmpl.Execute(w, ManageTmplData{Feeds: allFeeds})
|
|
||||||
}
|
|
||||||
|
|
||||||
var routeMap = map[string]http.HandlerFunc{
|
var routeMap = map[string]http.HandlerFunc{
|
||||||
"/": listContent,
|
"/": listContent,
|
||||||
"/about": about,
|
"/about": about,
|
||||||
|
@ -88,6 +14,10 @@ var routeMap = map[string]http.HandlerFunc{
|
||||||
"/ping": healthcheck,
|
"/ping": healthcheck,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bgTasks = []BackgroundTask{
|
||||||
|
{refreshFeeds, 10 * time.Minute},
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
SharedCache = &Datastore{
|
SharedCache = &Datastore{
|
||||||
Data: map[string]string{},
|
Data: map[string]string{},
|
||||||
|
@ -97,18 +27,5 @@ func main() {
|
||||||
SharedCache = existingStore
|
SharedCache = existingStore
|
||||||
}
|
}
|
||||||
|
|
||||||
api := API{StaticRoot: "./static"}
|
NewApp(routeMap, bgTasks, "./static").Start(":9000")
|
||||||
|
|
||||||
for route, handler := range routeMap {
|
|
||||||
api.AddRoute(route, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
refreshFeeds()
|
|
||||||
time.Sleep(10 * time.Minute)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
api.Start(":9000")
|
|
||||||
}
|
}
|
||||||
|
|
79
routes.go
Normal file
79
routes.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Link struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
PublishedDate string `json:"publishedDate"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Healthcheck route
|
||||||
|
//
|
||||||
|
// Confirms that the app is alive without guarantees
|
||||||
|
// about it being fully-functional.
|
||||||
|
func healthcheck(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
// About page
|
||||||
|
//
|
||||||
|
// Static content for the about page.
|
||||||
|
func about(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tmpl, _ := template.New("about.html.tmpl").ParseFiles("templates/about.html.tmpl")
|
||||||
|
tmpl.Execute(w, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feeds list
|
||||||
|
//
|
||||||
|
// Lists all feed elements in store.
|
||||||
|
func listContent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
links := []Link{}
|
||||||
|
for _, feed := range SharedCache.List("feeds") {
|
||||||
|
var formattedItems []Link
|
||||||
|
json.Unmarshal([]byte(feed), &formattedItems)
|
||||||
|
links = append(links, formattedItems...)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, _ := template.New("index.html.tmpl").ParseFiles("templates/index.html.tmpl")
|
||||||
|
tmpl.Execute(w, links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manage content
|
||||||
|
//
|
||||||
|
// Interface to add new feed subscriptions and get a list
|
||||||
|
// of current subs.
|
||||||
|
func manageContent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method == "POST" {
|
||||||
|
r.ParseForm()
|
||||||
|
|
||||||
|
urlValue := r.PostFormValue("url")
|
||||||
|
|
||||||
|
if _, err := url.Parse(urlValue); err != nil {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheKey := fmt.Sprintf("feedurl:%s", urlValue)
|
||||||
|
SharedCache.Set(cacheKey, urlValue)
|
||||||
|
|
||||||
|
go fetchFeed(urlValue)
|
||||||
|
|
||||||
|
w.WriteHeader(201)
|
||||||
|
}
|
||||||
|
|
||||||
|
allFeeds := SharedCache.List("feedurl")
|
||||||
|
|
||||||
|
type ManageTmplData struct {
|
||||||
|
Feeds map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, _ := template.New("manage.html.tmpl").ParseFiles("templates/manage.html.tmpl")
|
||||||
|
tmpl.Execute(w, ManageTmplData{Feeds: allFeeds})
|
||||||
|
}
|
Loading…
Reference in a new issue