💾 Archived View for source.community › ckaznocha › cliftons-capsule › raw › main › gemlog.go captured on 2021-12-17 at 13:26:06.
-=-=-=-=-=-=-
package main import ( "bufio" "bytes" "fmt" "io/fs" "net/url" "sort" "strings" "sync" "time" ) type entryMetadata struct { Filename string Date time.Time Title []byte } type entry struct { Metadata *entryMetadata Body []byte } type gemlog struct { gemlogFS fs.FS entrySet map[string]*entryMetadata entryList []*entryMetadata mu sync.RWMutex } func (g *gemlog) list() ([]*entryMetadata, error) { g.mu.Lock() defer g.mu.Unlock() if err := g.populate(); err != nil { return nil, err } return g.entryList, nil } func (g *gemlog) entry(path string) (*entry, bool) { g.mu.RLock() defer g.mu.RUnlock() path, err := url.QueryUnescape(strings.TrimPrefix(path, "/")) if err != nil { return nil, false } metadata, ok := g.entrySet[path] if !ok { return nil, false } f, err := fs.ReadFile(g.gemlogFS, path) if err != nil { return nil, false } return &entry{ Metadata: metadata, Body: bytes.TrimSpace(f[bytes.Index(f, []byte{'\n'})+1:]), }, true } func (g *gemlog) populate() error { dirInfo, err := fs.ReadDir(g.gemlogFS, "gemlog") if err != nil { return fmt.Errorf("cannot read gemlog dir: %w", err) } if len(g.entryList) == len(dirInfo) { return nil } g.entryList = []*entryMetadata{} g.entrySet = map[string]*entryMetadata{} if err := fs.WalkDir(g.gemlogFS, "gemlog", g.walkFS); err != nil { return fmt.Errorf("cannot walk gemlog dir: %w", err) } sort.Stable(g) return nil } func (g *gemlog) Len() int { return len(g.entryList) } func (g *gemlog) Swap(i, j int) { g.entryList[i], g.entryList[j] = g.entryList[j], g.entryList[i] } func (g *gemlog) Less(i, j int) bool { return g.entryList[i].Filename >= g.entryList[j].Filename } func (g *gemlog) walkFS(path string, d fs.DirEntry, e error) error { if e != nil { return e } if d.IsDir() { return nil } t, err := time.Parse(time.RFC3339[:10], d.Name()[:10]) if err != nil { return fmt.Errorf("unable to parse time stamp: %w", err) } f, err := g.gemlogFS.Open(path) if err != nil { return fmt.Errorf("unable to open file: %w", err) } title, err := bufio.NewReader(f).ReadBytes('\n') if err != nil { return fmt.Errorf("unable to read title: %w", err) } metadata := &entryMetadata{ Filename: d.Name(), Date: t, Title: bytes.TrimSpace(bytes.TrimPrefix(title, []byte{'#'})), } g.entrySet[path] = metadata g.entryList = append(g.entryList, metadata) return nil }