Skip to content

Commit

Permalink
feat: add download method for talebook service.
Browse files Browse the repository at this point in the history
  • Loading branch information
syhily committed Nov 15, 2022
1 parent fffcfa5 commit 90d5f86
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 37 deletions.
21 changes: 17 additions & 4 deletions internal/fetcher/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"github.com/bookstairs/bookhunter/internal/client"
)

var (
ErrOverrideRedirectHandler = errors.New("couldn't override the existed redirect handler")
)

type (
Format string // The supported file extension.
Category string // The fetcher service identity.
Expand Down Expand Up @@ -65,7 +69,7 @@ func (c *Config) Property(name string) string {

func (c *Config) SetRedirect(redirect func(request *http.Request, requests []*http.Request) error) error {
if c.Config.Redirect != nil {
return errors.New("couldn't override the existed redirect handler")
return ErrOverrideRedirectHandler
}
c.Config.Redirect = resty.RedirectPolicyFunc(redirect)

Expand All @@ -76,15 +80,24 @@ func (c *Config) SetRedirect(redirect func(request *http.Request, requests []*ht
func ParseFormats(formats []string) ([]Format, error) {
var fs []Format
for _, format := range formats {
f := Format(strings.ToLower(format))
if !IsValidFormat(f) {
return nil, fmt.Errorf("invalid format %s", format)
f, err := ParseFormat(format)
if err != nil {
return nil, err
}
fs = append(fs, f)
}
return fs, nil
}

// ParseFormat will create the format from the string.
func ParseFormat(format string) (Format, error) {
f := Format(strings.ToLower(format))
if !IsValidFormat(f) {
return "", fmt.Errorf("invalid format %s", format)
}
return f, nil
}

// IsValidFormat judge if this format was supported.
func IsValidFormat(format Format) bool {
switch format {
Expand Down
41 changes: 24 additions & 17 deletions internal/fetcher/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (f *commonFetcher) startDownload() {
// The error will be sent to the channel.

// Acquire the available file formats
formats, err := f.service.formats()
formats, err := f.service.formats(bookID)
if err != nil {
f.finishDownload(err)
break
Expand All @@ -98,19 +98,26 @@ func (f *commonFetcher) startDownload() {
formats = f.filterFormats(formats)

// Download the file by formats one by one.
for _, format := range formats {
err := f.downloadFile(bookID, format)
for format, url := range formats {
err := f.downloadFile(bookID, format, url)
if err != nil {
f.finishDownload(err)
break
}
}

// Save the download progress
err = f.progress.SaveBookID(bookID)
if err != nil {
f.finishDownload(err)
break
}
}
}

// downloadFile in a thread.
func (f *commonFetcher) downloadFile(bookID int64, format Format) error {
file, err := f.service.fetch(bookID, format)
func (f *commonFetcher) downloadFile(bookID int64, format Format, url string) error {
file, err := f.service.fetch(bookID, format, url)
if err != nil {
return err
}
Expand Down Expand Up @@ -164,24 +171,24 @@ func (f *commonFetcher) downloadFile(bookID int64, format Format) error {
return nil
}

// finishDownload will exist the download thread.
func (f *commonFetcher) finishDownload(err error) {
if err != nil {
f.errs <- err
}
f.wait.Done()
}

// filterFormats will find the valid formats by user configure.
func (f *commonFetcher) filterFormats(formats []Format) []Format {
var fs []Format
for _, format := range formats {
func (f *commonFetcher) filterFormats(formats map[Format]string) map[Format]string {
fs := make(map[Format]string)
for format, url := range formats {
for _, vf := range f.Formats {
if format == vf {
fs = append(fs, format)
fs[format] = url
break
}
}
}
return fs
}

// finishDownload will exist the download thread.
func (f *commonFetcher) finishDownload(err error) {
if err != nil {
f.errs <- err
}
f.wait.Done()
}
4 changes: 2 additions & 2 deletions internal/fetcher/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ type service interface {
size() (int64, error)

// formats will query the available downloadable file formats.
formats() ([]Format, error)
formats(id int64) (map[Format]string, error)

// fetch the given book ID.
fetch(id int64, format Format) (*fetch, error)
fetch(id int64, format Format, url string) (*fetch, error)
}

// fetch is the result which can be created from a resty.Response
Expand Down
86 changes: 72 additions & 14 deletions internal/fetcher/talebook.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ package fetcher
import (
"errors"
"net/http"
"strconv"

"github.com/bookstairs/bookhunter/internal/client"
"github.com/bookstairs/bookhunter/internal/log"
"github.com/bookstairs/bookhunter/internal/talebook"
)

var ErrTalebookNeedSignin = errors.New("need user account to download books")
var (
ErrTalebookNeedSignin = errors.New("need user account to download books")
ErrEmptyTalebook = errors.New("couldn't find available books in talebook")

redirectHandler = func(request *http.Request, requests []*http.Request) error {
if request.URL.Path == "/login" {
return ErrTalebookNeedSignin
}
return nil
}
)

type talebookService struct {
config *Config
Expand All @@ -18,13 +29,7 @@ type talebookService struct {

func newTalebookService(config *Config) (service, error) {
// Add login check in redirect handler.
err := config.SetRedirect(func(request *http.Request, requests []*http.Request) error {
if request.URL.Path == "/login" {
return ErrTalebookNeedSignin
}
return nil
})
if err != nil {
if err := config.SetRedirect(redirectHandler); err != nil {
return nil, err
}

Expand Down Expand Up @@ -67,14 +72,67 @@ func newTalebookService(config *Config) (service, error) {
}

func (t *talebookService) size() (int64, error) {
panic("implement me")
resp, err := t.client.R().
SetResult(&talebook.BooksResp{}).
Get("/api/recent")
if err != nil {
return 0, err
}

result := resp.Result().(*talebook.BooksResp)
if result.Err != talebook.SuccessStatus {
return 0, errors.New(result.Msg)
}

bookID := int64(0)
for _, book := range result.Books {
if book.ID > bookID {
bookID = book.ID
}
}

if bookID == 0 {
return 0, ErrEmptyTalebook
}

return bookID, nil
}

func (t *talebookService) formats() ([]Format, error) {
panic("implement me")
func (t *talebookService) formats(id int64) (map[Format]string, error) {
resp, err := t.client.R().
SetResult(&talebook.BookResp{}).
SetPathParam("bookID", strconv.FormatInt(id, 10)).
Get("/api/book/{bookID}")
if err != nil {
return nil, err
}

result := resp.Result().(*talebook.BookResp)
switch result.Err {
case talebook.SuccessStatus:
formats := make(map[Format]string)
for _, file := range result.Book.Files {
format, err := ParseFormat(file.Format)
if err != nil {
return nil, err
}
formats[format] = file.Href
}
return formats, nil
case talebook.BookNotFoundStatus:
return nil, nil
default:
return nil, errors.New(result.Msg)
}
}

func (t *talebookService) fetch(id int64, format Format) (*fetch, error) {
f := createFetch(nil)
return f, nil
func (t *talebookService) fetch(_ int64, _ Format, url string) (*fetch, error) {
resp, err := t.client.R().
SetDoNotParseResponse(true).
Get(url)
if err != nil {
return nil, err
}

return createFetch(resp), nil
}

0 comments on commit 90d5f86

Please sign in to comment.