commit e48f0422427ae70cc25ac8b2c39a671eca141898 from: Oliver Lowe date: Wed Apr 10 04:07:00 2024 UTC lemmy, lemmy/fs: have comments as entries in post directories commit - c8d63abe544d1425ee432f5c96ec28f9254e7de0 commit + e48f0422427ae70cc25ac8b2c39a671eca141898 blob - f3ab816fca856ca32427ba87310a265f045fb83d blob + 6d2879c6eeac9346f577d13ae7e63840f80280d8 --- client.go +++ client.go @@ -135,9 +135,9 @@ func (c *Client) Posts(community string, mode ListMode params := map[string]string{ "community_name": community, - "limit": "30", - "type_": string(mode), - "sort": "New", + // "limit": "30", + "type_": string(mode), + "sort": "New", } resp, err := c.get("post/list", params) if err != nil { blob - 737cdeff0457724aa4257ced480808449601ece2 blob + 605b1a4b77e149252b6236d64f044a0630fc3255 --- fs/file.go +++ fs/file.go @@ -75,21 +75,21 @@ func (f *dummy) ReadDir(n int) ([]fs.DirEntry, error) return f.dirinfo.ReadDir(n) } -type comFile struct { - name string +type lFile struct { + info fs.FileInfo dirinfo *dirInfo client *lemmy.Client buf io.ReadCloser } -func (f *comFile) Read(p []byte) (int, error) { +func (f *lFile) Read(p []byte) (int, error) { if f.buf == nil { f.buf = io.NopCloser(strings.NewReader("directory")) } return f.buf.Read(p) } -func (f *comFile) Close() error { +func (f *lFile) Close() error { if f.buf == nil || f.dirinfo == nil { return fs.ErrClosed } @@ -99,36 +99,40 @@ func (f *comFile) Close() error { return err } -func (f *comFile) Stat() (fs.FileInfo, error) { - community, _, err := f.client.LookupCommunity(f.name) - if err != nil { - return nil, &fs.PathError{"stat", f.name, err} - } - return &community, nil +func (f *lFile) Stat() (fs.FileInfo, error) { + return f.info, nil } -func (f *comFile) ReadDir(n int) ([]fs.DirEntry, error) { +func (f *lFile) ReadDir(n int) ([]fs.DirEntry, error) { if f.dirinfo == nil { f.dirinfo = new(dirInfo) - posts, err := f.client.Posts(f.name, lemmy.ListAll) - if err != nil { - return nil, &fs.PathError{"readdir", f.name, err} - } - for _, post := range posts { - post := post - f.dirinfo.entries = append(f.dirinfo.entries, fs.FileInfoToDirEntry(&post)) - comments, err := f.client.Comments(post.ID, lemmy.ListAll) + switch f.info.(type) { + case *lemmy.Community: + posts, err := f.client.Posts(f.info.Name(), lemmy.ListAll) if err != nil { - return nil, &fs.PathError{"readdir", f.name, err} + return nil, &fs.PathError{"readdir", f.info.Name(), err} } - for i := range comments { - f.dirinfo.entries = append(f.dirinfo.entries, fs.FileInfoToDirEntry(&comments[i])) + for _, p := range posts { + p := p + f.dirinfo.entries = append(f.dirinfo.entries, fs.FileInfoToDirEntry(&p)) } + case *lemmy.Post: + p := f.info.(*lemmy.Post) + comments, err := f.client.Comments(p.ID, lemmy.ListAll) + if err != nil { + return nil, &fs.PathError{"readdir", f.info.Name(), err} + } + for _, c := range comments { + c := c + f.dirinfo.entries = append(f.dirinfo.entries, fs.FileInfoToDirEntry(&c)) + } + default: + return nil, &fs.PathError{"readdir", f.info.Name(), fmt.Errorf("not a directory")} } } return f.dirinfo.ReadDir(n) } -func postFile(p *lemmy.Post) *dummy { +func postText(p *lemmy.Post) *bytes.Buffer { buf := &bytes.Buffer{} fmt.Fprintln(buf, "From:", p.CreatorID) fmt.Fprintf(buf, "Message-Id: <%d>\n", p.ID) @@ -140,15 +144,10 @@ func postFile(p *lemmy.Post) *dummy { fmt.Fprintln(buf, p.URL) } fmt.Fprintln(buf, p.Body) - return &dummy{ - name: p.Name(), - mode: p.Mode(), - mtime: p.ModTime(), - buf: io.NopCloser(buf), - } + return buf } -func commentFile(c *lemmy.Comment) *dummy { +func commentText(c *lemmy.Comment) *bytes.Buffer { buf := &bytes.Buffer{} fmt.Fprintln(buf, "From:", c.CreatorID) fmt.Fprintln(buf, "Date:", c.ModTime().Format(time.RFC822)) @@ -157,10 +156,5 @@ func commentFile(c *lemmy.Comment) *dummy { fmt.Fprintln(buf, "Subject: Re:", c.PostID) fmt.Fprintln(buf) fmt.Fprintln(buf, c.Content) - return &dummy{ - name: c.Name(), - mode: c.Mode(), - mtime: c.ModTime(), - buf: io.NopCloser(buf), - } + return buf } blob - 6d1f3609b1b649e5af5e55d0971bae105b3cfaf3 blob + 77cd53b4dd55e445d66dfc46f9e648ebb44357da --- fs/fs.go +++ fs/fs.go @@ -67,7 +67,7 @@ func (fsys *FS) Open(name string) (fs.File, error) { elems := strings.Split(name, "/") // We've only got communities, then posts/comments. // Anything deeper cannot exist. - if len(elems) >= 3 { + if len(elems) > 3 { return nil, &fs.PathError{"open", name, fs.ErrNotExist} } @@ -83,8 +83,8 @@ func (fsys *FS) Open(name string) (fs.File, error) { fsys.Communities[elems[0]] = community } if len(elems) == 1 { - return &comFile{ - name: community.Name(), + return &lFile{ + info: &community, buf: io.NopCloser(strings.NewReader(community.Name())), client: fsys.Client, }, nil @@ -92,23 +92,37 @@ func (fsys *FS) Open(name string) (fs.File, error) { id, err := strconv.Atoi(elems[1]) if err != nil { - return nil, &fs.PathError{"open", name, fmt.Errorf("bad post/comment id")} + return nil, &fs.PathError{"open", name, fmt.Errorf("bad post id")} } - - comment, err := fsys.Client.LookupComment(id) - if err == nil { - return commentFile(&comment), nil - } else if !errors.Is(err, lemmy.ErrNotFound) { + post, err := fsys.Client.LookupPost(id) + if errors.Is(err, lemmy.ErrNotFound) { + return nil, &fs.PathError{"open", name, fs.ErrNotExist} + } else if err != nil { return nil, &fs.PathError{"open", name, err} } + if len(elems) == 2 { + return &lFile{ + info: &post, + buf: io.NopCloser(strings.NewReader(post.Name())), + client: fsys.Client, + }, nil + } - post, err := fsys.Client.LookupPost(comment.PostID) + id, err = strconv.Atoi(elems[2]) + if err != nil { + return nil, &fs.PathError{"open", name, fmt.Errorf("bad comment id")} + } + comment, err := fsys.Client.LookupComment(id) if errors.Is(err, lemmy.ErrNotFound) { return nil, &fs.PathError{"open", name, fs.ErrNotExist} } else if err != nil { return nil, &fs.PathError{"open", name, err} } - return postFile(&post), nil + return &lFile{ + info: &comment, + buf: io.NopCloser(commentText(&comment)), + client: fsys.Client, + }, nil } func (fsys *FS) openRoot() (fs.File, error) { blob - 5a2535c9b22ecc0063639e072d0752be579754a9 blob + 334017bb586e4f41c0446025d447371b743c024e --- fs/fs_test.go +++ fs/fs_test.go @@ -1,6 +1,7 @@ package fs import ( + "io/fs" "net/http" "testing" "testing/fstest" @@ -23,8 +24,12 @@ func TestFS(t *testing.T) { if err != nil { t.Fatal(err) } + _, err = fs.ReadFile(fsys, "zzztestcommunity1/447/331") + if err != nil { + t.Fatal(err) + } - if err := fstest.TestFS(fsys, "zzztestcommunity1", "zzztestcommunity1/447/title", "zzztestcommunity1/447/331"); err != nil { + if err := fstest.TestFS(fsys, "zzztestcommunity1", "zzztestcommunity1/447/post", "zzztestcommunity1/447/331"); err != nil { t.Fatal(err) } } blob - bfd8c68f667c8b63dc9833c24659b00d7a55acba blob + 5cd7fe34aff26c2b4021d73e29266fc0377733e7 --- lemmy.go +++ lemmy.go @@ -22,7 +22,7 @@ func (c *Community) Name() string { return c.Str func (c *Community) Size() int64 { return 0 } func (c *Community) Mode() fs.FileMode { return fs.ModeDir | 0o0555 } func (c *Community) ModTime() time.Time { return c.Published } -func (c *Community) IsDir() bool { return true } +func (c *Community) IsDir() bool { return c.Mode().IsDir() } func (c *Community) Sys() interface{} { return nil } func (c Community) String() string { @@ -51,9 +51,9 @@ func (p *Post) Size() int64 { return int64(len(p.Body)) } -func (p *Post) Mode() fs.FileMode { return fs.ModeDir | 0o0444 } +func (p *Post) Mode() fs.FileMode { return fs.ModeDir | 0o0555 } func (p *Post) ModTime() time.Time { return p.Published } -func (p *Post) IsDir() bool { return true } +func (p *Post) IsDir() bool { return p.Mode().IsDir() } func (p *Post) Sys() interface{} { return nil } type Comment struct {