Blame


1 1081cf75 2024-11-04 o package fs
2 1081cf75 2024-11-04 o
3 1081cf75 2024-11-04 o import (
4 1081cf75 2024-11-04 o "bytes"
5 1081cf75 2024-11-04 o "fmt"
6 1081cf75 2024-11-04 o "io"
7 1081cf75 2024-11-04 o "io/fs"
8 1081cf75 2024-11-04 o "strings"
9 1081cf75 2024-11-04 o "time"
10 1081cf75 2024-11-04 o
11 1081cf75 2024-11-04 o "olowe.co/apub/lemmy"
12 1081cf75 2024-11-04 o )
13 1081cf75 2024-11-04 o
14 1081cf75 2024-11-04 o type fakeStat struct {
15 1081cf75 2024-11-04 o name string
16 1081cf75 2024-11-04 o size int64
17 1081cf75 2024-11-04 o mode fs.FileMode
18 1081cf75 2024-11-04 o mtime time.Time
19 1081cf75 2024-11-04 o }
20 1081cf75 2024-11-04 o
21 1081cf75 2024-11-04 o func (s *fakeStat) Name() string { return s.name }
22 1081cf75 2024-11-04 o func (s *fakeStat) Size() int64 { return s.size }
23 1081cf75 2024-11-04 o func (s *fakeStat) Mode() fs.FileMode { return s.mode }
24 1081cf75 2024-11-04 o func (s *fakeStat) ModTime() time.Time { return s.mtime }
25 1081cf75 2024-11-04 o func (s *fakeStat) IsDir() bool { return s.mode.IsDir() }
26 1081cf75 2024-11-04 o func (s *fakeStat) Sys() any { return nil }
27 1081cf75 2024-11-04 o
28 1081cf75 2024-11-04 o type dummy struct {
29 1081cf75 2024-11-04 o name string
30 1081cf75 2024-11-04 o mode fs.FileMode
31 1081cf75 2024-11-04 o mtime time.Time
32 1081cf75 2024-11-04 o contents []byte
33 1081cf75 2024-11-04 o dirinfo *dirInfo
34 1081cf75 2024-11-04 o buf io.ReadCloser
35 1081cf75 2024-11-04 o }
36 1081cf75 2024-11-04 o
37 1081cf75 2024-11-04 o func (f *dummy) Name() string { return f.name }
38 1081cf75 2024-11-04 o func (f *dummy) IsDir() bool { return f.mode.IsDir() }
39 1081cf75 2024-11-04 o func (f *dummy) Type() fs.FileMode { return f.mode.Type() }
40 1081cf75 2024-11-04 o func (f *dummy) Info() (fs.FileInfo, error) { return f.Stat() }
41 1081cf75 2024-11-04 o
42 1081cf75 2024-11-04 o func (f *dummy) Stat() (fs.FileInfo, error) {
43 1081cf75 2024-11-04 o return &fakeStat{
44 1081cf75 2024-11-04 o name: f.name,
45 1081cf75 2024-11-04 o mode: f.mode,
46 1081cf75 2024-11-04 o size: int64(len(f.contents)),
47 1081cf75 2024-11-04 o mtime: f.mtime,
48 1081cf75 2024-11-04 o }, nil
49 1081cf75 2024-11-04 o }
50 1081cf75 2024-11-04 o
51 1081cf75 2024-11-04 o func (f *dummy) Read(p []byte) (int, error) {
52 1081cf75 2024-11-04 o if f.buf == nil {
53 1081cf75 2024-11-04 o f.buf = io.NopCloser(bytes.NewReader(f.contents))
54 1081cf75 2024-11-04 o }
55 1081cf75 2024-11-04 o return f.buf.Read(p)
56 1081cf75 2024-11-04 o }
57 1081cf75 2024-11-04 o
58 1081cf75 2024-11-04 o func (f *dummy) Close() error {
59 1081cf75 2024-11-04 o if f.buf == nil {
60 1081cf75 2024-11-04 o return nil
61 1081cf75 2024-11-04 o }
62 1081cf75 2024-11-04 o err := f.buf.Close()
63 1081cf75 2024-11-04 o f.buf = nil
64 1081cf75 2024-11-04 o return err
65 1081cf75 2024-11-04 o }
66 1081cf75 2024-11-04 o
67 1081cf75 2024-11-04 o func (f *dummy) ReadDir(n int) ([]fs.DirEntry, error) {
68 1081cf75 2024-11-04 o if !f.mode.IsDir() {
69 1081cf75 2024-11-04 o return nil, &fs.PathError{"readdir", f.name, fmt.Errorf("not a directory")}
70 1081cf75 2024-11-04 o } else if f.dirinfo == nil {
71 1081cf75 2024-11-04 o // TODO(otl): is this accidental? maybe return an error here.
72 1081cf75 2024-11-04 o return nil, &fs.PathError{"readdir", f.name, fmt.Errorf("no dirinfo to track reads")}
73 1081cf75 2024-11-04 o }
74 1081cf75 2024-11-04 o
75 1081cf75 2024-11-04 o return f.dirinfo.ReadDir(n)
76 1081cf75 2024-11-04 o }
77 1081cf75 2024-11-04 o
78 1081cf75 2024-11-04 o type lFile struct {
79 1081cf75 2024-11-04 o info fs.FileInfo
80 1081cf75 2024-11-04 o dirinfo *dirInfo
81 1081cf75 2024-11-04 o client *lemmy.Client
82 1081cf75 2024-11-04 o buf io.ReadCloser
83 1081cf75 2024-11-04 o }
84 1081cf75 2024-11-04 o
85 1081cf75 2024-11-04 o func (f *lFile) Read(p []byte) (int, error) {
86 1081cf75 2024-11-04 o if f.buf == nil {
87 1081cf75 2024-11-04 o f.buf = io.NopCloser(strings.NewReader("directory"))
88 1081cf75 2024-11-04 o }
89 1081cf75 2024-11-04 o return f.buf.Read(p)
90 1081cf75 2024-11-04 o }
91 1081cf75 2024-11-04 o
92 1081cf75 2024-11-04 o func (f *lFile) Close() error {
93 1081cf75 2024-11-04 o if f.buf == nil || f.dirinfo == nil {
94 1081cf75 2024-11-04 o return fs.ErrClosed
95 1081cf75 2024-11-04 o }
96 1081cf75 2024-11-04 o f.dirinfo = nil
97 1081cf75 2024-11-04 o err := f.buf.Close()
98 1081cf75 2024-11-04 o f.buf = nil
99 1081cf75 2024-11-04 o return err
100 1081cf75 2024-11-04 o }
101 1081cf75 2024-11-04 o
102 1081cf75 2024-11-04 o func (f *lFile) Stat() (fs.FileInfo, error) {
103 1081cf75 2024-11-04 o return f.info, nil
104 1081cf75 2024-11-04 o }
105 1081cf75 2024-11-04 o
106 1081cf75 2024-11-04 o func (f *lFile) ReadDir(n int) ([]fs.DirEntry, error) {
107 1081cf75 2024-11-04 o if f.dirinfo == nil {
108 1081cf75 2024-11-04 o f.dirinfo = new(dirInfo)
109 1081cf75 2024-11-04 o switch f.info.(type) {
110 1081cf75 2024-11-04 o case *lemmy.Community:
111 1081cf75 2024-11-04 o posts, err := f.client.Posts(f.info.Name(), lemmy.ListAll)
112 1081cf75 2024-11-04 o if err != nil {
113 1081cf75 2024-11-04 o return nil, &fs.PathError{"readdir", f.info.Name(), err}
114 1081cf75 2024-11-04 o }
115 1081cf75 2024-11-04 o for _, p := range posts {
116 1081cf75 2024-11-04 o p := p
117 1081cf75 2024-11-04 o f.dirinfo.entries = append(f.dirinfo.entries, fs.FileInfoToDirEntry(&p))
118 1081cf75 2024-11-04 o }
119 1081cf75 2024-11-04 o case *lemmy.Post:
120 1081cf75 2024-11-04 o p := f.info.(*lemmy.Post)
121 1081cf75 2024-11-04 o comments, err := f.client.Comments(p.ID, lemmy.ListAll)
122 1081cf75 2024-11-04 o if err != nil {
123 1081cf75 2024-11-04 o return nil, &fs.PathError{"readdir", f.info.Name(), err}
124 1081cf75 2024-11-04 o }
125 1081cf75 2024-11-04 o for _, c := range comments {
126 1081cf75 2024-11-04 o c := c
127 1081cf75 2024-11-04 o f.dirinfo.entries = append(f.dirinfo.entries, fs.FileInfoToDirEntry(&c))
128 1081cf75 2024-11-04 o }
129 1081cf75 2024-11-04 o f.dirinfo.entries = append(f.dirinfo.entries, postFile(p))
130 1081cf75 2024-11-04 o default:
131 1081cf75 2024-11-04 o return nil, &fs.PathError{"readdir", f.info.Name(), fmt.Errorf("not a directory")}
132 1081cf75 2024-11-04 o }
133 1081cf75 2024-11-04 o }
134 1081cf75 2024-11-04 o return f.dirinfo.ReadDir(n)
135 1081cf75 2024-11-04 o }
136 1081cf75 2024-11-04 o func postText(p *lemmy.Post) *bytes.Buffer {
137 1081cf75 2024-11-04 o buf := &bytes.Buffer{}
138 1081cf75 2024-11-04 o fmt.Fprintln(buf, "From:", p.CreatorID)
139 1081cf75 2024-11-04 o fmt.Fprintf(buf, "Message-Id: <%d>\n", p.ID)
140 1081cf75 2024-11-04 o fmt.Fprintf(buf, "List-Archive: <%s>\n", p.URL)
141 1081cf75 2024-11-04 o fmt.Fprintln(buf, "Date:", p.ModTime().Format(time.RFC822))
142 1081cf75 2024-11-04 o fmt.Fprintln(buf, "Subject:", p.Title)
143 1081cf75 2024-11-04 o fmt.Fprintln(buf)
144 1081cf75 2024-11-04 o if p.URL != "" {
145 1081cf75 2024-11-04 o fmt.Fprintln(buf, p.URL)
146 1081cf75 2024-11-04 o }
147 1081cf75 2024-11-04 o fmt.Fprintln(buf, p.Body)
148 1081cf75 2024-11-04 o return buf
149 1081cf75 2024-11-04 o }
150 1081cf75 2024-11-04 o
151 1081cf75 2024-11-04 o func postFile(p *lemmy.Post) *dummy {
152 1081cf75 2024-11-04 o return &dummy{
153 1081cf75 2024-11-04 o name: "post",
154 1081cf75 2024-11-04 o mode: 0o444,
155 1081cf75 2024-11-04 o mtime: p.ModTime(),
156 1081cf75 2024-11-04 o contents: postText(p).Bytes(),
157 1081cf75 2024-11-04 o }
158 1081cf75 2024-11-04 o }
159 1081cf75 2024-11-04 o
160 1081cf75 2024-11-04 o func commentText(c *lemmy.Comment) *bytes.Buffer {
161 1081cf75 2024-11-04 o buf := &bytes.Buffer{}
162 1081cf75 2024-11-04 o fmt.Fprintln(buf, "From:", c.CreatorID)
163 1081cf75 2024-11-04 o fmt.Fprintln(buf, "Date:", c.ModTime().Format(time.RFC822))
164 1081cf75 2024-11-04 o fmt.Fprintf(buf, "Message-ID: <%d>\n", c.ID)
165 1081cf75 2024-11-04 o fmt.Fprintf(buf, "List-Archive: <%s>\n", c.ActivityURL)
166 1081cf75 2024-11-04 o fmt.Fprintln(buf, "Subject: Re:", c.PostID)
167 1081cf75 2024-11-04 o fmt.Fprintln(buf)
168 1081cf75 2024-11-04 o fmt.Fprintln(buf, c.Content)
169 1081cf75 2024-11-04 o return buf
170 1081cf75 2024-11-04 o }