init: pristine aerc 0.20.0 source
This commit is contained in:
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.sr.ht/~rockorager/go-jmap"
|
||||
)
|
||||
|
||||
func (c *JMAPCache) GetBlob(id jmap.ID) ([]byte, error) {
|
||||
fpath := c.blobPath(id)
|
||||
if fpath == "" {
|
||||
return nil, notfound
|
||||
}
|
||||
return os.ReadFile(fpath)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutBlob(id jmap.ID, buf []byte) error {
|
||||
fpath := c.blobPath(id)
|
||||
if fpath == "" {
|
||||
return nil
|
||||
}
|
||||
_ = os.MkdirAll(path.Dir(fpath), 0o700)
|
||||
return os.WriteFile(fpath, buf, 0o600)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) DeleteBlob(id jmap.ID) error {
|
||||
fpath := c.blobPath(id)
|
||||
if fpath == "" {
|
||||
return nil
|
||||
}
|
||||
defer func() {
|
||||
_ = os.Remove(path.Dir(fpath))
|
||||
}()
|
||||
return os.Remove(fpath)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) blobPath(id jmap.ID) string {
|
||||
if c.blobsDir == "" || id == "" {
|
||||
return ""
|
||||
}
|
||||
name := string(id)
|
||||
sub := name[len(name)-2:]
|
||||
return path.Join(c.blobsDir, sub, name)
|
||||
}
|
||||
Vendored
+109
@@ -0,0 +1,109 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"git.sr.ht/~rjarry/aerc/lib/log"
|
||||
"git.sr.ht/~rjarry/aerc/lib/xdg"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
)
|
||||
|
||||
type JMAPCache struct {
|
||||
mem map[string][]byte
|
||||
file *leveldb.DB
|
||||
blobsDir string
|
||||
}
|
||||
|
||||
func NewJMAPCache(state, blobs bool, accountName string) *JMAPCache {
|
||||
c := new(JMAPCache)
|
||||
cacheDir := xdg.CachePath()
|
||||
if state && cacheDir != "" {
|
||||
var err error
|
||||
dir := path.Join(cacheDir, "aerc", accountName, "state")
|
||||
_ = os.MkdirAll(dir, 0o700)
|
||||
c.file, err = leveldb.OpenFile(dir, nil)
|
||||
if err != nil {
|
||||
log.Errorf("failed to open goleveldb: %s", err)
|
||||
c.mem = make(map[string][]byte)
|
||||
}
|
||||
} else {
|
||||
c.mem = make(map[string][]byte)
|
||||
}
|
||||
if blobs && cacheDir != "" {
|
||||
c.blobsDir = path.Join(cacheDir, "aerc", accountName, "blobs")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
var notfound = errors.New("key not found")
|
||||
|
||||
func (c *JMAPCache) get(key string) ([]byte, error) {
|
||||
switch {
|
||||
case c.file != nil:
|
||||
return c.file.Get([]byte(key), nil)
|
||||
case c.mem != nil:
|
||||
value, ok := c.mem[key]
|
||||
if !ok {
|
||||
return nil, notfound
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
panic("jmap cache with no backend")
|
||||
}
|
||||
|
||||
func (c *JMAPCache) put(key string, value []byte) error {
|
||||
switch {
|
||||
case c.file != nil:
|
||||
return c.file.Put([]byte(key), value, nil)
|
||||
case c.mem != nil:
|
||||
c.mem[key] = value
|
||||
return nil
|
||||
}
|
||||
panic("jmap cache with no backend")
|
||||
}
|
||||
|
||||
func (c *JMAPCache) delete(key string) error {
|
||||
switch {
|
||||
case c.file != nil:
|
||||
return c.file.Delete([]byte(key), nil)
|
||||
case c.mem != nil:
|
||||
delete(c.mem, key)
|
||||
return nil
|
||||
}
|
||||
panic("jmap cache with no backend")
|
||||
}
|
||||
|
||||
func (c *JMAPCache) purge(prefix string) error {
|
||||
switch {
|
||||
case c.file != nil:
|
||||
txn, err := c.file.OpenTransaction()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
iter := txn.NewIterator(util.BytesPrefix([]byte(prefix)), nil)
|
||||
for iter.Next() {
|
||||
err = txn.Delete(iter.Key(), nil)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
iter.Release()
|
||||
if err != nil {
|
||||
txn.Discard()
|
||||
return err
|
||||
}
|
||||
return txn.Commit()
|
||||
case c.mem != nil:
|
||||
for key := range c.mem {
|
||||
if strings.HasPrefix(key, prefix) {
|
||||
delete(c.mem, key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
panic("jmap cache with no backend")
|
||||
}
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"git.sr.ht/~rockorager/go-jmap"
|
||||
"git.sr.ht/~rockorager/go-jmap/mail/email"
|
||||
)
|
||||
|
||||
func (c *JMAPCache) HasEmail(id jmap.ID) bool {
|
||||
_, err := c.get(emailKey(id))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) GetEmail(id jmap.ID) (*email.Email, error) {
|
||||
buf, err := c.get(emailKey(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e := new(email.Email)
|
||||
err = unmarshal(buf, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutEmail(id jmap.ID, e *email.Email) error {
|
||||
buf, err := marshal(e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.put(emailKey(id), buf)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) DeleteEmail(id jmap.ID) error {
|
||||
return c.delete(emailKey(id))
|
||||
}
|
||||
|
||||
func emailKey(id jmap.ID) string {
|
||||
return "email/" + string(id)
|
||||
}
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"git.sr.ht/~rjarry/aerc/lib/log"
|
||||
"git.sr.ht/~rjarry/aerc/worker/types"
|
||||
"git.sr.ht/~rockorager/go-jmap"
|
||||
)
|
||||
|
||||
type FolderContents struct {
|
||||
MailboxID jmap.ID
|
||||
QueryState string
|
||||
Filter *types.SearchCriteria
|
||||
Sort []*types.SortCriterion
|
||||
MessageIDs []jmap.ID
|
||||
}
|
||||
|
||||
func (c *JMAPCache) GetFolderContents(mailboxId jmap.ID) (*FolderContents, error) {
|
||||
key := folderContentsKey(mailboxId)
|
||||
buf, err := c.get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := new(FolderContents)
|
||||
err = unmarshal(buf, m)
|
||||
if err != nil {
|
||||
log.Debugf("cache format has changed, purging foldercontents")
|
||||
if e := c.purge("foldercontents/"); e != nil {
|
||||
log.Errorf("foldercontents cache purge: %s", e)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutFolderContents(mailboxId jmap.ID, m *FolderContents) error {
|
||||
buf, err := marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.put(folderContentsKey(mailboxId), buf)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) DeleteFolderContents(mailboxId jmap.ID) error {
|
||||
return c.delete(folderContentsKey(mailboxId))
|
||||
}
|
||||
|
||||
func folderContentsKey(mailboxId jmap.ID) string {
|
||||
return "foldercontents/" + string(mailboxId)
|
||||
}
|
||||
|
||||
func (f *FolderContents) NeedsRefresh(
|
||||
filter *types.SearchCriteria, sort []*types.SortCriterion,
|
||||
) bool {
|
||||
return f.QueryState == "" ||
|
||||
!reflect.DeepEqual(f.Sort, sort) ||
|
||||
!reflect.DeepEqual(f.Filter, filter)
|
||||
}
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
|
||||
"git.sr.ht/~rockorager/go-jmap/mail/email"
|
||||
"git.sr.ht/~rockorager/go-jmap/mail/mailbox"
|
||||
)
|
||||
|
||||
type jmapObject interface {
|
||||
*email.Email |
|
||||
*email.QueryResponse |
|
||||
*mailbox.Mailbox |
|
||||
*FolderContents |
|
||||
*IDList
|
||||
}
|
||||
|
||||
func marshal[T jmapObject](obj T) ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
encoder := gob.NewEncoder(buf)
|
||||
err := encoder.Encode(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func unmarshal[T jmapObject](data []byte, obj T) error {
|
||||
buf := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(buf)
|
||||
return decoder.Decode(obj)
|
||||
}
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"git.sr.ht/~rockorager/go-jmap"
|
||||
"git.sr.ht/~rockorager/go-jmap/mail/mailbox"
|
||||
)
|
||||
|
||||
func (c *JMAPCache) GetMailbox(id jmap.ID) (*mailbox.Mailbox, error) {
|
||||
buf, err := c.get(mailboxKey(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := new(mailbox.Mailbox)
|
||||
err = unmarshal(buf, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutMailbox(id jmap.ID, m *mailbox.Mailbox) error {
|
||||
buf, err := marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.put(mailboxKey(id), buf)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) DeleteMailbox(id jmap.ID) error {
|
||||
return c.delete(mailboxKey(id))
|
||||
}
|
||||
|
||||
func mailboxKey(id jmap.ID) string {
|
||||
return "mailbox/" + string(id)
|
||||
}
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"git.sr.ht/~rockorager/go-jmap"
|
||||
)
|
||||
|
||||
type IDList struct {
|
||||
IDs []jmap.ID
|
||||
}
|
||||
|
||||
func (c *JMAPCache) GetMailboxList() ([]jmap.ID, error) {
|
||||
buf, err := c.get(mailboxListKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var list IDList
|
||||
err = unmarshal(buf, &list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list.IDs, nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutMailboxList(list []jmap.ID) error {
|
||||
buf, err := marshal(&IDList{IDs: list})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.put(mailboxListKey, buf)
|
||||
}
|
||||
|
||||
const mailboxListKey = "mailbox/list"
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"git.sr.ht/~rockorager/go-jmap"
|
||||
)
|
||||
|
||||
func (c *JMAPCache) GetSession() (*jmap.Session, error) {
|
||||
buf, err := c.get(sessionKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := new(jmap.Session)
|
||||
err = json.Unmarshal(buf, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutSession(s *jmap.Session) error {
|
||||
buf, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.put(sessionKey, buf)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) DeleteSession() error {
|
||||
return c.delete(sessionKey)
|
||||
}
|
||||
|
||||
const sessionKey = "session"
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
package cache
|
||||
|
||||
func (c *JMAPCache) GetMailboxState() (string, error) {
|
||||
buf, err := c.get(mailboxStateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutMailboxState(state string) error {
|
||||
return c.put(mailboxStateKey, []byte(state))
|
||||
}
|
||||
|
||||
func (c *JMAPCache) GetEmailState() (string, error) {
|
||||
buf, err := c.get(emailStateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutEmailState(state string) error {
|
||||
return c.put(emailStateKey, []byte(state))
|
||||
}
|
||||
|
||||
func (c *JMAPCache) GetThreadState() (string, error) {
|
||||
buf, err := c.get(threadStateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutThreadState(state string) error {
|
||||
return c.put(threadStateKey, []byte(state))
|
||||
}
|
||||
|
||||
const (
|
||||
mailboxStateKey = "state/mailbox"
|
||||
emailStateKey = "state/email"
|
||||
threadStateKey = "state/thread"
|
||||
)
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"git.sr.ht/~rockorager/go-jmap"
|
||||
)
|
||||
|
||||
func (c *JMAPCache) GetThread(id jmap.ID) ([]jmap.ID, error) {
|
||||
buf, err := c.get(threadKey(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var list IDList
|
||||
err = unmarshal(buf, &list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list.IDs, nil
|
||||
}
|
||||
|
||||
func (c *JMAPCache) PutThread(id jmap.ID, list []jmap.ID) error {
|
||||
buf, err := marshal(&IDList{IDs: list})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.put(threadKey(id), buf)
|
||||
}
|
||||
|
||||
func (c *JMAPCache) DeleteThread(id jmap.ID) error {
|
||||
return c.delete(mailboxKey(id))
|
||||
}
|
||||
|
||||
func threadKey(id jmap.ID) string {
|
||||
return "thread/" + string(id)
|
||||
}
|
||||
Reference in New Issue
Block a user