aboutsummaryrefslogtreecommitdiff
path: root/crane.go
diff options
context:
space:
mode:
authorJordan <me@jordan.im>2021-03-14 13:43:03 -0700
committerJordan <me@jordan.im>2021-03-14 13:43:03 -0700
commitf03d77f73be72a934a99541b30a9663cc99a1733 (patch)
tree5065869c40492ebb917e825b6bcf0075b5117a17 /crane.go
parentc0271039935407c232270cef74cd2f559f77a64e (diff)
downloadcrane-f03d77f73be72a934a99541b30a9663cc99a1733.tar.gz
crane-f03d77f73be72a934a99541b30a9663cc99a1733.zip
r/w map locks; concurrent safety
Diffstat (limited to 'crane.go')
-rw-r--r--crane.go39
1 files changed, 38 insertions, 1 deletions
diff --git a/crane.go b/crane.go
index 32e9a5f..bd5bb8a 100644
--- a/crane.go
+++ b/crane.go
@@ -17,6 +17,7 @@ import (
"os"
"path/filepath"
"strings"
+ "sync"
"golang.org/x/net/publicsuffix"
)
@@ -64,12 +65,13 @@ type Paper struct {
}
type Papers struct {
+ sync.RWMutex
List map[string]map[string]*Paper
Path string
}
type Resp struct {
- Papers map[string]map[string]*Paper
+ Papers Papers
Status string
LastPaperDL string
LastUsedCategory string
@@ -121,6 +123,7 @@ func getPaperFileNameFromResp(resp *http.Response) string {
func (papers *Papers) getUniqueName(category string, name string) string {
newName := name
ext := 2
+ papers.RLock()
for {
key := filepath.Join(category, newName+".pdf")
if _, exists := papers.List[category][key]; exists != true {
@@ -130,6 +133,7 @@ func (papers *Papers) getUniqueName(category string, name string) string {
ext++
}
}
+ papers.RUnlock()
return newName
}
@@ -142,6 +146,9 @@ func (papers *Papers) findPapersWalk(path string, info os.FileInfo,
return nil
}
+ papers.Lock()
+ defer papers.Unlock()
+
// derive category name (e.g. Mathematics) from directory name; used as key
var category string
if i, _ := os.Stat(path); i.IsDir() {
@@ -246,10 +253,12 @@ func (papers *Papers) NewPaperFromDOI(doi []byte, category string) (*Paper,
// if not matching, check if DOIs match (genuine duplicate)
if name != uniqueName {
key := filepath.Join(category, name+".pdf")
+ papers.RLock()
if meta.DOI == papers.List[category][key].Meta.DOI {
return nil, fmt.Errorf("paper %q with DOI %q already downloaded",
name, string(doi))
}
+ papers.RUnlock()
}
paper.PaperName = uniqueName
@@ -276,8 +285,11 @@ func (papers *Papers) NewPaperFromDOI(doi []byte, category string) (*Paper,
return nil, err
}
paper.Meta = *meta
+
+ papers.Lock()
papers.List[category][filepath.Join(category,
paper.PaperName+".pdf")] = &paper
+ papers.Unlock()
return &paper, nil
}
@@ -315,8 +327,10 @@ func (papers *Papers) NewPaperFromDirectLink(resp *http.Response, meta *Meta,
if err := renameFile(tmpPDF.Name(), paper.PaperPath); err != nil {
return nil, err
}
+ papers.Lock()
papers.List[category][filepath.Join(category,
paper.PaperName+".pdf")] = &paper
+ papers.Unlock()
return &paper, nil
}
@@ -325,6 +339,7 @@ func (papers *Papers) NewPaperFromDirectLink(resp *http.Response, meta *Meta,
func (papers *Papers) DeletePaper(paper string) error {
// check if the category in which the paper is said to belong
// exists
+ papers.RLock()
category := filepath.Dir(paper)
if _, exists := papers.List[category]; exists != true {
return fmt.Errorf("category %q does not exist\n",
@@ -336,9 +351,11 @@ func (papers *Papers) DeletePaper(paper string) error {
return fmt.Errorf("paper %q does not exist in category %q\n", paper,
category)
}
+ papers.RUnlock()
// paper and category exists and the paper belongs to the provided
// category; remove it and its XML metadata
+ papers.Lock()
if err := os.Remove(papers.List[category][paper].PaperPath); err != nil {
return err
}
@@ -353,31 +370,40 @@ func (papers *Papers) DeletePaper(paper string) error {
}
}
delete(papers.List[category], paper)
+ papers.Unlock()
return nil
}
// DeleteCategory deletes a category and its contents from the filesystem and
// the papers.List set
func (papers *Papers) DeleteCategory(category string) error {
+ papers.RLock()
if _, exists := papers.List[category]; exists != true {
return fmt.Errorf("category %q does not exist in the set\n", category)
}
+ papers.RUnlock()
+
+ papers.Lock()
if err := os.RemoveAll(filepath.Join(papers.Path, category)); err != nil {
return err
}
+
// remove subcategories (nested directories) which exist under the primary
for key, _ := range papers.List {
if strings.HasPrefix(key, category+"/") {
delete(papers.List, key)
}
}
+
delete(papers.List, category)
+ papers.Unlock()
return nil
}
// MovePaper moves a paper to the destination category on the filesystem and
// the papers.List set
func (papers *Papers) MovePaper(paper string, category string) error {
+ papers.RLock()
prevCategory := filepath.Dir(paper)
if _, exists := papers.List[prevCategory]; exists != true {
return fmt.Errorf("category %q does not exist\n", prevCategory)
@@ -393,6 +419,9 @@ func (papers *Papers) MovePaper(paper string, category string) error {
return fmt.Errorf("paper %q exists in destination category %q\n",
paper, category)
}
+ papers.RUnlock()
+
+ papers.Lock()
paperDest := filepath.Join(filepath.Join(papers.Path, category),
papers.List[prevCategory][paper].PaperName+".pdf")
if err := os.Rename(papers.List[prevCategory][paper].PaperPath, paperDest);
@@ -422,12 +451,15 @@ func (papers *Papers) MovePaper(paper string, category string) error {
}
}
delete(papers.List[prevCategory], paper)
+
+ papers.Unlock()
return nil
}
// RenameCategory renames a category on the filesystem and the paper.List set
func (papers *Papers) RenameCategory(oldCategory string,
newCategory string) error {
+ papers.RLock()
if _, exists := papers.List[oldCategory]; exists != true {
return fmt.Errorf("category %q does not exist in the set\n", oldCategory)
}
@@ -438,6 +470,9 @@ func (papers *Papers) RenameCategory(oldCategory string,
filepath.Join(papers.Path, newCategory)); err != nil {
return err
}
+ papers.RUnlock()
+
+ papers.Lock()
papers.List[newCategory] = make(map[string]*Paper)
for k, v := range papers.List[oldCategory] {
pPaperPath := filepath.Join(papers.Path, filepath.Join(newCategory,
@@ -453,6 +488,8 @@ func (papers *Papers) RenameCategory(oldCategory string,
}
}
delete(papers.List, oldCategory)
+
+ papers.Unlock()
return nil
}