From 3d8dd95c809e42b0d8ed6cda31391dada16289b6 Mon Sep 17 00:00:00 2001 From: Sinuhe Tellez Date: Thu, 10 Jun 2021 01:00:52 -0400 Subject: [PATCH 1/5] time now i called only when you run the service --- CHANGELOG.md | 4 ++++ internal/service/service.go | 17 +++++++++-------- internal/service/service_test.go | 6 +++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e7a0d..e934b31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.0] - 2021-06-10 +### Changed +- time is calculated only once + ## [0.0.11] - 2021-06-05 ### Changed - return to filepath as the best way to handle paths for different platforms. diff --git a/internal/service/service.go b/internal/service/service.go index 54c2c9b..4e43c33 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -34,7 +34,7 @@ type OPDS struct { AuthorURI string } -var TimeNowFunc = timeNow +var TimeNow = timeNowFunc() func (s OPDS) Handler(w http.ResponseWriter, req *http.Request) error { fPath := filepath.Join(s.DirRoot, req.URL.Path) @@ -57,14 +57,14 @@ func (s OPDS) Handler(w http.ResponseWriter, req *http.Request) error { } content = append([]byte(xml.Header), content...) - http.ServeContent(w, req, "feed.xml", TimeNowFunc(), bytes.NewReader(content)) + http.ServeContent(w, req, "feed.xml", TimeNow(), bytes.NewReader(content)) return nil } func (s OPDS) getContent(req *http.Request, dirpath string) (result []byte, err error) { feed := s.makeFeed(dirpath, req) if getPathType(dirpath) == pathTypeDirOfFiles { - acFeed := &opds.AcquisitionFeed{&feed, "http://purl.org/dc/terms/", "http://opds-spec.org/2010/catalog"} + acFeed := &opds.AcquisitionFeed{Feed: &feed, Dc: "http://purl.org/dc/terms/", Opds: "http://opds-spec.org/2010/catalog"} result, err = xml.MarshalIndent(acFeed, " ", " ") } else { result, err = xml.MarshalIndent(feed, " ", " ") @@ -79,7 +79,7 @@ func (s OPDS) makeFeed(dirpath string, req *http.Request) atom.Feed { ID(req.URL.Path). Title("Catalog in " + req.URL.Path). Author(opds.AuthorBuilder.Name(s.Author).Email(s.AuthorEmail).URI(s.AuthorURI).Build()). - Updated(TimeNowFunc()). + Updated(TimeNow()). AddLink(opds.LinkBuilder.Rel("start").Href("/").Type(navigationType).Build()) fis, _ := ioutil.ReadDir(dirpath) @@ -89,8 +89,8 @@ func (s OPDS) makeFeed(dirpath string, req *http.Request) atom.Feed { AddEntry(opds.EntryBuilder. ID(req.URL.Path + fi.Name()). Title(fi.Name()). - Updated(TimeNowFunc()). - Published(TimeNowFunc()). + Updated(TimeNow()). + Published(TimeNow()). AddLink(opds.LinkBuilder. Rel(getRel(fi.Name(), pathType)). Title(fi.Name()). @@ -153,6 +153,7 @@ func isFile(fi os.FileInfo) bool { return !fi.IsDir() } -func timeNow() time.Time { - return time.Now() +func timeNowFunc() func() time.Time { + t := time.Now() + return func() time.Time { return t } } diff --git a/internal/service/service_test.go b/internal/service/service_test.go index 33d321b..e1dcbfc 100644 --- a/internal/service/service_test.go +++ b/internal/service/service_test.go @@ -14,9 +14,9 @@ import ( func TestHandler(t *testing.T) { // pre-setup - nowFn := service.TimeNowFunc + nowFn := service.TimeNow defer func() { - service.TimeNowFunc = nowFn + service.TimeNow = nowFn }() tests := map[string]struct { @@ -36,7 +36,7 @@ func TestHandler(t *testing.T) { s := service.OPDS{"testdata", "", "", ""} w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, tc.input, nil) - service.TimeNowFunc = func() time.Time { + service.TimeNow = func() time.Time { return time.Date(2020, 05, 25, 00, 00, 00, 0, time.UTC) } From 622703cf5cec254354864ebcbd68f1b039ac9eb6 Mon Sep 17 00:00:00 2001 From: Sinuhe Tellez Date: Thu, 10 Jun 2021 02:18:53 -0400 Subject: [PATCH 2/5] refactor service handler --- internal/service/service.go | 54 +++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/internal/service/service.go b/internal/service/service.go index 4e43c33..dbefc2c 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -27,6 +27,12 @@ func init() { _ = mime.AddExtensionType(".fb2", "text/fb2+xml") } +const ( + pathTypeFile = iota + pathTypeDirOfDirs + pathTypeDirOfFiles +) + type OPDS struct { DirRoot string Author string @@ -36,40 +42,40 @@ type OPDS struct { var TimeNow = timeNowFunc() +// Handler serve the content of a book file or +// returns an Acquisition Feed when the entries are documents or +// returns an Navegation Feed when the entries are other folders func (s OPDS) Handler(w http.ResponseWriter, req *http.Request) error { fPath := filepath.Join(s.DirRoot, req.URL.Path) log.Printf("fPath:'%s'", fPath) - fi, err := os.Stat(fPath) - if err != nil { - return err - } - - if isFile(fi) { + if getPathType(fPath) == pathTypeFile { http.ServeFile(w, req, fPath) return nil } - content, err := s.getContent(req, fPath) + navFeed := s.makeFeed(fPath, req) + + var content []byte + var err error + if getPathType(fPath) == pathTypeDirOfFiles { + // if path is a directory of files it is an aquisition feed + acFeed := &opds.AcquisitionFeed{Feed: &navFeed, Dc: "http://purl.org/dc/terms/", Opds: "http://opds-spec.org/2010/catalog"} + content, err = xml.MarshalIndent(acFeed, " ", " ") + } else { + // if path is a directory of directories it is an aquisition feed + content, err = xml.MarshalIndent(navFeed, " ", " ") + } if err != nil { + log.Printf("error while serving '%s': %s", fPath, err) return err } content = append([]byte(xml.Header), content...) http.ServeContent(w, req, "feed.xml", TimeNow(), bytes.NewReader(content)) - return nil -} -func (s OPDS) getContent(req *http.Request, dirpath string) (result []byte, err error) { - feed := s.makeFeed(dirpath, req) - if getPathType(dirpath) == pathTypeDirOfFiles { - acFeed := &opds.AcquisitionFeed{Feed: &feed, Dc: "http://purl.org/dc/terms/", Opds: "http://opds-spec.org/2010/catalog"} - result, err = xml.MarshalIndent(acFeed, " ", " ") - } else { - result, err = xml.MarshalIndent(feed, " ", " ") - } - return + return nil } const navigationType = "application/atom+xml;profile=opds-catalog;kind=navigation" @@ -94,7 +100,7 @@ func (s OPDS) makeFeed(dirpath string, req *http.Request) atom.Feed { AddLink(opds.LinkBuilder. Rel(getRel(fi.Name(), pathType)). Title(fi.Name()). - Href(getHref(req, fi.Name())). + Href(filepath.Join(req.URL.RequestURI(), url.PathEscape(fi.Name()))). Type(getType(fi.Name(), pathType)). Build()). Build()) @@ -123,16 +129,6 @@ func getType(name string, pathType int) string { return "application/atom+xml;profile=opds-catalog;kind=acquisition" } -func getHref(req *http.Request, name string) string { - return filepath.Join(req.URL.RequestURI(), url.PathEscape(name)) -} - -const ( - pathTypeFile = iota - pathTypeDirOfDirs - pathTypeDirOfFiles -) - func getPathType(dirpath string) int { fi, _ := os.Stat(dirpath) if isFile(fi) { From cb46eb6817eec9342c38875df8e20dbf4f2a9b77 Mon Sep 17 00:00:00 2001 From: Sinuhe Tellez Date: Thu, 10 Jun 2021 02:40:08 -0400 Subject: [PATCH 3/5] change mimetype for xmls --- internal/service/service.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/service/service.go b/internal/service/service.go index dbefc2c..b77d60f 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -60,12 +60,12 @@ func (s OPDS) Handler(w http.ResponseWriter, req *http.Request) error { var content []byte var err error if getPathType(fPath) == pathTypeDirOfFiles { - // if path is a directory of files it is an aquisition feed acFeed := &opds.AcquisitionFeed{Feed: &navFeed, Dc: "http://purl.org/dc/terms/", Opds: "http://opds-spec.org/2010/catalog"} content, err = xml.MarshalIndent(acFeed, " ", " ") + w.Header().Add("Content-Type", "application/atom+xml;profile=opds-catalog;kind=acquisition") } else { - // if path is a directory of directories it is an aquisition feed content, err = xml.MarshalIndent(navFeed, " ", " ") + w.Header().Add("Content-Type", "application/atom+xml;profile=opds-catalog;kind=navigation") } if err != nil { log.Printf("error while serving '%s': %s", fPath, err) @@ -123,10 +123,16 @@ func getRel(name string, pathType int) string { } func getType(name string, pathType int) string { - if pathType == pathTypeFile { + switch pathType { + case pathTypeFile: return mime.TypeByExtension(filepath.Ext(name)) + case pathTypeDirOfFiles: + return "application/atom+xml;profile=opds-catalog;kind=acquisition" + case pathTypeDirOfDirs: + return "application/atom+xml;profile=opds-catalog;kind=navigation" + default: + return mime.TypeByExtension("xml") } - return "application/atom+xml;profile=opds-catalog;kind=acquisition" } func getPathType(dirpath string) int { From 23834555fd929f10a42c7f2f97ce8dde5f7c90d8 Mon Sep 17 00:00:00 2001 From: Sinuhe Tellez Date: Thu, 10 Jun 2021 02:40:47 -0400 Subject: [PATCH 4/5] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e934b31..cddeca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.0] - 2021-06-10 ### Changed - time is calculated only once +- updated the mimetype returned for the navigation and acquisition xmls ## [0.0.11] - 2021-06-05 ### Changed From 55148287233dbe89c0c5e081f7c9ad20616fb69e Mon Sep 17 00:00:00 2001 From: Sinuhe Tellez Date: Thu, 10 Jun 2021 02:55:39 -0400 Subject: [PATCH 5/5] fix unittests --- internal/service/service_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/service_test.go b/internal/service/service_test.go index e1dcbfc..434b8e1 100644 --- a/internal/service/service_test.go +++ b/internal/service/service_test.go @@ -24,8 +24,8 @@ func TestHandler(t *testing.T) { want string WantedContentType string }{ - "feed (dir of folders )": {input: "/", want: feed, WantedContentType: "application/xml"}, - "acquisitionFeed(dir of files)": {input: "/mybook", want: acquisitionFeed, WantedContentType: "application/xml"}, + "feed (dir of dirs )": {input: "/", want: feed, WantedContentType: "application/atom+xml;profile=opds-catalog;kind=navigation"}, + "acquisitionFeed(dir of files)": {input: "/mybook", want: acquisitionFeed, WantedContentType: "application/atom+xml;profile=opds-catalog;kind=acquisition"}, "servingAFile": {input: "/mybook/mybook.txt", want: "Fixture", WantedContentType: "text/plain; charset=utf-8"}, "serving file with spaces": {input: "/mybook/mybook%20copy.txt", want: "Fixture", WantedContentType: "text/plain; charset=utf-8"}, }