From 76cff9554001ca3727e2ba11b790e9bba27d6b77 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 17 May 2018 16:29:15 +0300 Subject: Move all cache to ~/.cache/gomuks Now `rm -rf ~/.cache/gomuks` has the same effect as `/clearcache` --- config/config.go | 260 ++++++++++++++++++++++++++++++++++++++++++++----- config/session.go | 137 -------------------------- config/session_test.go | 163 ------------------------------- 3 files changed, 237 insertions(+), 323 deletions(-) delete mode 100644 config/session.go delete mode 100644 config/session_test.go (limited to 'config') diff --git a/config/config.go b/config/config.go index cf080ff..41cff41 100644 --- a/config/config.go +++ b/config/config.go @@ -17,55 +17,90 @@ package config import ( - "fmt" "io/ioutil" "os" "path/filepath" "gopkg.in/yaml.v2" "maunium.net/go/gomuks/debug" + "maunium.net/go/gomuks/matrix/rooms" + "maunium.net/go/gomuks/matrix/pushrules" + "encoding/json" + "strings" + "maunium.net/go/gomatrix" ) // Config contains the main config of gomuks. type Config struct { - UserID string `yaml:"mxid"` - HS string `yaml:"homeserver"` + UserID string `yaml:"mxid"` + AccessToken string `yaml:"access_token"` + HS string `yaml:"homeserver"` - Dir string `yaml:"-"` - HistoryDir string `yaml:"history_dir"` - MediaDir string `yaml:"media_dir"` - Session *Session `yaml:"-"` + Dir string `yaml:"-"` + CacheDir string `yaml:"cache_dir"` + HistoryDir string `yaml:"history_dir"` + MediaDir string `yaml:"media_dir"` + StateDir string `yaml:"state_dir"` + + AuthCache struct { + NextBatch string `yaml:"next_batch"` + FilterID string `yaml:"filter_id"` + InitialSyncDone bool `yaml:"initial_sync_done"` + } `yaml:"-"` + + Rooms map[string]*rooms.Room `yaml:"-"` + PushRules *pushrules.PushRuleset `yaml:"-"` + + nosave bool } // NewConfig creates a config that loads data from the given directory. func NewConfig(configDir, cacheDir string) *Config { return &Config{ Dir: configDir, + CacheDir: cacheDir, HistoryDir: filepath.Join(cacheDir, "history"), + StateDir: filepath.Join(cacheDir, "state"), MediaDir: filepath.Join(cacheDir, "media"), + + Rooms: make(map[string]*rooms.Room), } } // Clear clears the session cache and removes all history. func (config *Config) Clear() { - if config.Session != nil { - config.Session.Clear() - } os.RemoveAll(config.HistoryDir) + os.RemoveAll(config.StateDir) os.RemoveAll(config.MediaDir) + os.RemoveAll(config.CacheDir) + config.nosave = true } -func (config *Config) DeleteSession() { - if config.Session != nil { - os.Remove(config.Session.path) - config.Session = nil - } - os.RemoveAll(config.HistoryDir) - os.RemoveAll(config.MediaDir) +func (config *Config) CreateCacheDirs() { + os.MkdirAll(config.CacheDir, 0700) os.MkdirAll(config.HistoryDir, 0700) + os.MkdirAll(config.StateDir, 0700) os.MkdirAll(config.MediaDir, 0700) } +func (config *Config) DeleteSession() { + config.AuthCache.NextBatch = "" + config.AuthCache.InitialSyncDone = false + config.Rooms = make(map[string]*rooms.Room) + config.PushRules = nil + + config.Clear() + config.nosave = false + config.CreateCacheDirs() +} + +func (config *Config) LoadAll() { + config.Load() + config.LoadAuthCache() + config.LoadPushRules() + config.LoadRooms() +} + // Load loads the config from config.yaml in the directory given to the config struct. func (config *Config) Load() { os.MkdirAll(config.Dir, 0700) @@ -74,25 +109,34 @@ func (config *Config) Load() { data, err := ioutil.ReadFile(configPath) if err != nil { if os.IsNotExist(err) { - os.MkdirAll(config.HistoryDir, 0700) - os.MkdirAll(config.MediaDir, 0700) + config.CreateCacheDirs() return } - fmt.Println("Failed to read config from", configPath) + debug.Print("Failed to read config from", configPath) panic(err) } err = yaml.Unmarshal(data, &config) if err != nil { - fmt.Println("Failed to parse config at", configPath) + debug.Print("Failed to parse config at", configPath) panic(err) } - os.MkdirAll(config.HistoryDir, 0700) - os.MkdirAll(config.MediaDir, 0700) + config.CreateCacheDirs() +} + +func (config *Config) SaveAll() { + config.Save() + config.SaveAuthCache() + config.SavePushRules() + config.SaveRooms() } // Save saves this config to config.yaml in the directory given to the config struct. func (config *Config) Save() { + if config.nosave { + return + } + os.MkdirAll(config.Dir, 0700) data, err := yaml.Marshal(&config) if err != nil { @@ -107,3 +151,173 @@ func (config *Config) Save() { panic(err) } } + +func (config *Config) LoadAuthCache() { + os.MkdirAll(config.Dir, 0700) + + configPath := filepath.Join(config.CacheDir, "auth-cache.yaml") + data, err := ioutil.ReadFile(configPath) + if err != nil { + if os.IsNotExist(err) { + return + } + debug.Print("Failed to read auth cache from", configPath) + panic(err) + } + + err = yaml.Unmarshal(data, &config.AuthCache) + if err != nil { + debug.Print("Failed to parse auth cache at", configPath) + panic(err) + } +} + +func (config *Config) SaveAuthCache() { + if config.nosave { + return + } + + os.MkdirAll(config.CacheDir, 0700) + data, err := yaml.Marshal(&config.AuthCache) + if err != nil { + debug.Print("Failed to marshal auth cache") + panic(err) + } + + path := filepath.Join(config.CacheDir, "auth-cache.yaml") + err = ioutil.WriteFile(path, data, 0600) + if err != nil { + debug.Print("Failed to write auth cache to", path) + panic(err) + } +} + +func (config *Config) LoadPushRules() { + os.MkdirAll(config.CacheDir, 0700) + + pushRulesPath := filepath.Join(config.CacheDir, "pushrules.json") + data, err := ioutil.ReadFile(pushRulesPath) + if err != nil { + if os.IsNotExist(err) { + return + } + debug.Print("Failed to read push rules from", pushRulesPath) + return + } + + config.PushRules = &pushrules.PushRuleset{} + err = json.Unmarshal(data, &config.PushRules) + if err != nil { + debug.Print("Failed to parse push rules at", pushRulesPath) + return + } +} + +func (config *Config) SavePushRules() { + if config.nosave || config.PushRules == nil { + return + } + + os.MkdirAll(config.CacheDir, 0700) + data, err := json.Marshal(&config.PushRules) + if err != nil { + debug.Print("Failed to marshal push rules") + return + } + + path := filepath.Join(config.CacheDir, "pushrules.json") + err = ioutil.WriteFile(path, data, 0600) + if err != nil { + debug.Print("Failed to write config to", path) + return + } +} + +func (config *Config) LoadRooms() { + os.MkdirAll(config.StateDir, 0700) + + roomFiles, err := ioutil.ReadDir(config.StateDir) + if err != nil { + debug.Print("Failed to list rooms state caches in", config.StateDir) + panic(err) + } + + for _, roomFile := range roomFiles { + if roomFile.IsDir() || !strings.HasSuffix(roomFile.Name(), ".gmxstate") { + continue + } + path := filepath.Join(config.StateDir, roomFile.Name()) + room := &rooms.Room{} + err = room.Load(path) + if err != nil { + debug.Printf("Failed to load room state cache from %s: %v", path, err) + continue + } + config.Rooms[room.ID] = room + } +} + +func (config *Config) SaveRooms() { + if config.nosave { + return + } + + os.MkdirAll(config.StateDir, 0700) + for _, room := range config.Rooms { + path := config.getRoomCachePath(room) + err := room.Save(path) + if err != nil { + debug.Printf("Failed to save room state cache to file %s: %v", path, err) + } + } +} + +func (config *Config) GetUserID() string { + return config.UserID +} + +func (config *Config) SaveFilterID(_, filterID string) { + config.AuthCache.FilterID = filterID + config.SaveAuthCache() +} + +func (config *Config) LoadFilterID(_ string) string { + return config.AuthCache.FilterID +} + +func (config *Config) SaveNextBatch(_, nextBatch string) { + config.AuthCache.NextBatch = nextBatch + config.SaveAuthCache() +} + +func (config *Config) LoadNextBatch(_ string) string { + return config.AuthCache.NextBatch +} + +func (config *Config) GetRoom(roomID string) *rooms.Room { + room, _ := config.Rooms[roomID] + if room == nil { + room = rooms.NewRoom(roomID, config.UserID) + config.Rooms[room.ID] = room + } + return room +} + +func (config *Config) getRoomCachePath(room *rooms.Room) string { + return filepath.Join(config.StateDir, room.ID+".gmxstate") +} + +func (config *Config) PutRoom(room *rooms.Room) { + config.Rooms[room.ID] = room + room.Save(config.getRoomCachePath(room)) +} + +func (config *Config) SaveRoom(room *gomatrix.Room) { + gmxRoom := config.GetRoom(room.ID) + gmxRoom.Room = room + gmxRoom.Save(config.getRoomCachePath(gmxRoom)) +} + +func (config *Config) LoadRoom(roomID string) *gomatrix.Room { + return config.GetRoom(roomID).Room +} diff --git a/config/session.go b/config/session.go deleted file mode 100644 index d23c778..0000000 --- a/config/session.go +++ /dev/null @@ -1,137 +0,0 @@ -// gomuks - A terminal Matrix client written in Go. -// Copyright (C) 2018 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -package config - -import ( - "encoding/json" - "io/ioutil" - "path/filepath" - - "maunium.net/go/gomatrix" - "maunium.net/go/gomuks/debug" - "maunium.net/go/gomuks/matrix/pushrules" - "maunium.net/go/gomuks/matrix/rooms" -) - -type Session struct { - UserID string `json:"-"` - path string - AccessToken string - NextBatch string - FilterID string - Rooms map[string]*rooms.Room - PushRules *pushrules.PushRuleset - - InitialSyncDone bool -} - -func (config *Config) LoadSession(mxid string) error { - config.Session = config.NewSession(mxid) - return config.Session.Load() -} - -func (config *Config) NewSession(mxid string) *Session { - return &Session{ - UserID: mxid, - path: filepath.Join(config.Dir, mxid+".session"), - Rooms: make(map[string]*rooms.Room), - } -} - -func (s *Session) GetUserID() string { - return s.UserID -} - -func (s *Session) Clear() { - s.Rooms = make(map[string]*rooms.Room) - s.PushRules = nil - s.NextBatch = "" - s.FilterID = "" - s.InitialSyncDone = false - s.Save() -} - -func (s *Session) Load() error { - data, err := ioutil.ReadFile(s.path) - if err != nil { - debug.Printf("Failed to read session from %s: %v", s.path, err) - return err - } - - err = json.Unmarshal(data, s) - if err != nil { - debug.Printf("Failed to parse session at %s: %v", s.path, err) - return err - } - return nil -} - -func (s *Session) Save() error { - data, err := json.Marshal(s) - if err != nil { - debug.Printf("Failed to marshal session of %s: %v", s.UserID, err) - return err - } - - err = ioutil.WriteFile(s.path, data, 0600) - if err != nil { - debug.Printf("Failed to write session of %s to %s: %v", s.UserID, s.path, err) - return err - } - return nil -} - -func (s *Session) LoadFilterID(_ string) string { - return s.FilterID -} - -func (s *Session) LoadNextBatch(_ string) string { - return s.NextBatch -} - -func (s *Session) GetRoom(mxid string) *rooms.Room { - room, _ := s.Rooms[mxid] - if room == nil { - room = rooms.NewRoom(mxid, s.UserID) - s.Rooms[room.ID] = room - } - return room -} - -func (s *Session) PutRoom(room *rooms.Room) { - s.Rooms[room.ID] = room - s.Save() -} - -func (s *Session) SaveFilterID(_, filterID string) { - s.FilterID = filterID - s.Save() -} - -func (s *Session) SaveNextBatch(_, nextBatch string) { - s.NextBatch = nextBatch - s.Save() -} - -func (s *Session) LoadRoom(mxid string) *gomatrix.Room { - return s.GetRoom(mxid).Room -} - -func (s *Session) SaveRoom(room *gomatrix.Room) { - s.GetRoom(room.ID).Room = room - s.Save() -} diff --git a/config/session_test.go b/config/session_test.go deleted file mode 100644 index 5a7558b..0000000 --- a/config/session_test.go +++ /dev/null @@ -1,163 +0,0 @@ -// gomuks - A terminal Matrix client written in Go. -// Copyright (C) 2018 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -package config_test - -import ( - "testing" - "maunium.net/go/gomuks/config" - "github.com/stretchr/testify/assert" - "os" -) - -func TestConfig_NewSession(t *testing.T) { - defer os.RemoveAll("/tmp/gomuks-test-7") - - cfg := config.NewConfig("/tmp/gomuks-test-7", "/tmp/gomuks-test-7") - cfg.Load() - session := cfg.NewSession("@tulir:maunium.net") - assert.Equal(t, session.GetUserID(), "@tulir:maunium.net") - assert.Empty(t, session.Rooms) - - _, err1 := os.Stat("/tmp/gomuks-test-7/@tulir:maunium.net.session") - assert.True(t, os.IsNotExist(err1)) - assert.Nil(t, session.Save()) - _, err2 := os.Stat("/tmp/gomuks-test-7/@tulir:maunium.net.session") - assert.Nil(t, err2) -} - -func TestSession_Load(t *testing.T) { - defer os.RemoveAll("/tmp/gomuks-test-8") - - cfg := config.NewConfig("/tmp/gomuks-test-8", "/tmp/gomuks-test-8") - cfg.Load() - session := cfg.NewSession("@tulir:maunium.net") - session.SaveNextBatch("@tulir:maunium.net", "foobar") - session.SaveFilterID("@tulir:maunium.net", "1234") - - cfg = config.NewConfig("/tmp/gomuks-test-8", "/tmp/gomuks-test-8") - cfg.LoadSession("@tulir:maunium.net") - assert.NotNil(t, cfg.Session) - assert.Equal(t, "foobar", cfg.Session.LoadNextBatch("@tulir:maunium.net")) - assert.Equal(t, "1234", cfg.Session.LoadFilterID("@tulir:maunium.net")) -} - -func TestSession_Clear(t *testing.T) { - defer os.RemoveAll("/tmp/gomuks-test-9") - - cfg := config.NewConfig("/tmp/gomuks-test-9", "/tmp/gomuks-test-9") - cfg.Load() - session := cfg.NewSession("@tulir:maunium.net") - session.SaveNextBatch("@tulir:maunium.net", "foobar") - session.SaveFilterID("@tulir:maunium.net", "1234") - - cfg = config.NewConfig("/tmp/gomuks-test-9", "/tmp/gomuks-test-9") - cfg.LoadSession("@tulir:maunium.net") - assert.NotNil(t, cfg.Session) - assert.Equal(t, "foobar", cfg.Session.LoadNextBatch("@tulir:maunium.net")) - assert.Equal(t, "1234", cfg.Session.LoadFilterID("@tulir:maunium.net")) - - cfg.Session.Clear() - assert.Empty(t, cfg.Session.FilterID) - assert.Empty(t, cfg.Session.NextBatch) - assert.Empty(t, cfg.Session.Rooms) - - cfg = config.NewConfig("/tmp/gomuks-test-9", "/tmp/gomuks-test-9") - cfg.LoadSession("@tulir:maunium.net") - assert.Empty(t, cfg.Session.FilterID) - assert.Empty(t, cfg.Session.NextBatch) - assert.Empty(t, cfg.Session.Rooms) -} - -func TestConfig_ClearWithSession(t *testing.T) { - defer os.RemoveAll("/tmp/gomuks-test-9") - - cfg := config.NewConfig("/tmp/gomuks-test-9", "/tmp/gomuks-test-9") - cfg.Load() - session := cfg.NewSession("@tulir:maunium.net") - session.SaveNextBatch("@tulir:maunium.net", "foobar") - session.SaveFilterID("@tulir:maunium.net", "1234") - - cfg = config.NewConfig("/tmp/gomuks-test-9", "/tmp/gomuks-test-9") - cfg.LoadSession("@tulir:maunium.net") - assert.NotNil(t, cfg.Session) - assert.Equal(t, "foobar", cfg.Session.LoadNextBatch("@tulir:maunium.net")) - assert.Equal(t, "1234", cfg.Session.LoadFilterID("@tulir:maunium.net")) - - cfg.Clear() - assert.Empty(t, cfg.Session.FilterID) - assert.Empty(t, cfg.Session.NextBatch) - assert.Empty(t, cfg.Session.Rooms) - - cfg = config.NewConfig("/tmp/gomuks-test-9", "/tmp/gomuks-test-9") - cfg.LoadSession("@tulir:maunium.net") - assert.Empty(t, cfg.Session.FilterID) - assert.Empty(t, cfg.Session.NextBatch) - assert.Empty(t, cfg.Session.Rooms) -} - -func TestSession_GetRoom(t *testing.T) { - defer os.RemoveAll("/tmp/gomuks-test-10") - - cfg := config.NewConfig("/tmp/gomuks-test-10", "/tmp/gomuks-test-10") - cfg.Session = cfg.NewSession("@tulir:maunium.net") - room := cfg.Session.GetRoom("!foo:maunium.net") - assert.NotNil(t, room) - assert.Equal(t, room.Room, cfg.Session.LoadRoom("!foo:maunium.net")) -} - -func TestSession_PutRoom(t *testing.T) { - defer os.RemoveAll("/tmp/gomuks-test-11") - - cfg := config.NewConfig("/tmp/gomuks-test-11", "/tmp/gomuks-test-11") - cfg.Load() - cfg.LoadSession("@tulir:maunium.net") - room := cfg.Session.GetRoom("!foo:maunium.net") - room.PrevBatch = "foobar" - room.HasLeft = true - cfg.Session.PutRoom(room) - - cfg = config.NewConfig("/tmp/gomuks-test-11", "/tmp/gomuks-test-11") - cfg.LoadSession("@tulir:maunium.net") - reloadedRoom := cfg.Session.GetRoom("!foo:maunium.net") - assert.Equal(t, "foobar", reloadedRoom.PrevBatch, "%v %v", room, reloadedRoom) - assert.True(t, reloadedRoom.HasLeft, "%v %v", room, reloadedRoom) -} - -func TestConfig_DeleteSession(t *testing.T) { - defer os.RemoveAll("/tmp/gomuks-test-12") - - cfg := config.NewConfig("/tmp/gomuks-test-12", "/tmp/gomuks-test-12") - cfg.Load() - cfg.LoadSession("@tulir:maunium.net") - cfg.Session.SaveNextBatch("@tulir:maunium.net", "foobar") - cfg.Session.SaveFilterID("@tulir:maunium.net", "1234") - - cfg.DeleteSession() - - assert.Nil(t, cfg.Session) - - sessFile, err := os.Stat("/tmp/gomuks-test-12/@tulir:maunium.net.session") - assert.Nil(t, sessFile) - assert.True(t, os.IsNotExist(err)) - - mediaDir, err := os.Stat("/tmp/gomuks-test-12/media") - assert.True(t, mediaDir.IsDir()) - assert.Nil(t, err) - historyDir, err := os.Stat("/tmp/gomuks-test-12/history") - assert.True(t, historyDir.IsDir()) - assert.Nil(t, err) -} -- cgit v1.2.3