aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTulir Asokan <tulir@maunium.net>2018-03-22 19:51:20 +0200
committerTulir Asokan <tulir@maunium.net>2018-03-22 19:54:31 +0200
commit702a75a8c0355737e3e62735b59fe30bee7e42f4 (patch)
tree538b2acd579eabf893fd1f63bc7093b65b620f28
parent232f7fe1be917bf91f6342946f6d001948b8559e (diff)
Save history to disk. Fixes #1
-rw-r--r--config/config.go24
-rw-r--r--config/session.go12
-rw-r--r--gomuks.go29
-rw-r--r--interface/ui.go1
-rw-r--r--ui/types/message.go16
-rw-r--r--ui/view-main.go24
-rw-r--r--ui/widget/message-view.go53
-rw-r--r--ui/widget/room-view.go13
8 files changed, 147 insertions, 25 deletions
diff --git a/config/config.go b/config/config.go
index 7d99274..5c1d87c 100644
--- a/config/config.go
+++ b/config/config.go
@@ -30,19 +30,29 @@ type Config struct {
UserID string `yaml:"mxid"`
HS string `yaml:"homeserver"`
- dir string `yaml:"-"`
- Session *Session `yaml:"-"`
+ Dir string `yaml:"-"`
+ HistoryDir string `yaml:"history_dir"`
+ Session *Session `yaml:"-"`
}
func NewConfig(dir string) *Config {
return &Config{
- dir: dir,
+ Dir: dir,
+ HistoryDir: filepath.Join(dir, "history"),
}
}
+func (config *Config) Clear() {
+ if config.Session != nil {
+ config.Session.Clear()
+ }
+ os.RemoveAll(config.HistoryDir)
+}
+
func (config *Config) Load() {
- os.MkdirAll(config.dir, 0700)
- configPath := filepath.Join(config.dir, "config.yaml")
+ os.MkdirAll(config.Dir, 0700)
+ os.MkdirAll(config.HistoryDir, 0700)
+ configPath := filepath.Join(config.Dir, "config.yaml")
data, err := ioutil.ReadFile(configPath)
if err != nil {
if os.IsNotExist(err) {
@@ -61,14 +71,14 @@ func (config *Config) Load() {
}
func (config *Config) Save() {
- os.MkdirAll(config.dir, 0700)
+ os.MkdirAll(config.Dir, 0700)
data, err := yaml.Marshal(&config)
if err != nil {
debug.Print("Failed to marshal config")
panic(err)
}
- path := filepath.Join(config.dir, "config.yaml")
+ path := filepath.Join(config.Dir, "config.yaml")
err = ioutil.WriteFile(path, data, 0600)
if err != nil {
debug.Print("Failed to write config to", path)
diff --git a/config/session.go b/config/session.go
index 3fdc169..2d4b885 100644
--- a/config/session.go
+++ b/config/session.go
@@ -23,7 +23,7 @@ import (
"maunium.net/go/gomatrix"
"maunium.net/go/gomuks/matrix/pushrules"
- rooms "maunium.net/go/gomuks/matrix/room"
+ "maunium.net/go/gomuks/matrix/room"
"maunium.net/go/gomuks/ui/debug"
)
@@ -45,7 +45,7 @@ func (config *Config) LoadSession(mxid string) error {
func (config *Config) NewSession(mxid string) *Session {
return &Session{
UserID: mxid,
- path: filepath.Join(config.dir, mxid+".session"),
+ path: filepath.Join(config.Dir, mxid+".session"),
Rooms: make(map[string]*rooms.Room),
}
}
@@ -61,13 +61,13 @@ func (s *Session) Clear() {
func (s *Session) Load() error {
data, err := ioutil.ReadFile(s.path)
if err != nil {
- debug.Print("Failed to read session from", s.path, err)
+ debug.Printf("Failed to read session from %s: %v", s.path, err)
return err
}
err = json.Unmarshal(data, s)
if err != nil {
- debug.Print("Failed to parse session at", s.path, err)
+ debug.Printf("Failed to parse session at %s: %v", s.path, err)
return err
}
return nil
@@ -76,13 +76,13 @@ func (s *Session) Load() error {
func (s *Session) Save() error {
data, err := json.Marshal(s)
if err != nil {
- debug.Print("Failed to marshal session of", s.UserID, err)
+ 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.Print("Failed to write session to", s.path, err)
+ debug.Printf("Failed to write session of %s to %s: %v", s.UserID, s.path, err)
return err
}
return nil
diff --git a/gomuks.go b/gomuks.go
index 6429f24..2dbbdff 100644
--- a/gomuks.go
+++ b/gomuks.go
@@ -38,12 +38,14 @@ type Gomuks struct {
debug *debug.Pane
debugMode bool
config *config.Config
+ stop chan bool
}
func NewGomuks(enableDebug bool) *Gomuks {
configDir := filepath.Join(os.Getenv("HOME"), ".config/gomuks")
gmx := &Gomuks{
- app: tview.NewApplication(),
+ app: tview.NewApplication(),
+ stop: make(chan bool, 1),
}
gmx.debug = debug.NewPane()
@@ -79,11 +81,33 @@ func (gmx *Gomuks) Stop() {
gmx.matrix.Stop()
gmx.debug.Print("Cleaning up UI...")
gmx.app.Stop()
+ gmx.stop <- true
+ gmx.Save()
+ os.Exit(0)
+}
+
+func (gmx *Gomuks) Save() {
if gmx.config.Session != nil {
gmx.debug.Print("Saving session...")
gmx.config.Session.Save()
}
- os.Exit(0)
+ gmx.debug.Print("Saving history...")
+ gmx.ui.MainView().SaveAllHistory()
+}
+
+func (gmx *Gomuks) StartAutosave() {
+ defer gmx.Recover()
+ ticker := time.NewTicker(time.Minute)
+ for {
+ select {
+ case <-ticker.C:
+ gmx.Save()
+ case val := <-gmx.stop:
+ if val {
+ return
+ }
+ }
+ }
}
func (gmx *Gomuks) Recover() {
@@ -101,6 +125,7 @@ func (gmx *Gomuks) Recover() {
func (gmx *Gomuks) Start() {
defer gmx.Recover()
+ go gmx.StartAutosave()
if err := gmx.app.Run(); err != nil {
panic(err)
}
diff --git a/interface/ui.go b/interface/ui.go
index 36a733b..bded310 100644
--- a/interface/ui.go
+++ b/interface/ui.go
@@ -44,6 +44,7 @@ type MainView interface {
AddRoom(roomID string)
RemoveRoom(roomID string)
SetRooms(roomIDs []string)
+ SaveAllHistory()
SetTyping(roomID string, users []string)
AddServiceMessage(roomID string, message string)
diff --git a/ui/types/message.go b/ui/types/message.go
index 6775597..e6ded4a 100644
--- a/ui/types/message.go
+++ b/ui/types/message.go
@@ -28,7 +28,7 @@ type Message struct {
BasicMeta
ID string
Text string
- Buffer []string
+ buffer []string
prevBufferWidth int
}
@@ -64,12 +64,12 @@ func (message *Message) CalculateBuffer(width int) {
if width < 2 {
return
}
- message.Buffer = []string{}
+ message.buffer = []string{}
forcedLinebreaks := strings.Split(message.Text, "\n")
newlines := 0
for _, str := range forcedLinebreaks {
if len(str) == 0 && newlines < 1 {
- message.Buffer = append(message.Buffer, "")
+ message.buffer = append(message.buffer, "")
newlines++
} else {
newlines = 0
@@ -87,7 +87,7 @@ func (message *Message) CalculateBuffer(width int) {
extract = extract[:matches[len(matches)-1][1]]
}
}
- message.Buffer = append(message.Buffer, extract)
+ message.buffer = append(message.buffer, extract)
str = str[len(extract):]
}
}
@@ -97,3 +97,11 @@ func (message *Message) CalculateBuffer(width int) {
func (message *Message) RecalculateBuffer() {
message.CalculateBuffer(message.prevBufferWidth)
}
+
+func (message *Message) Buffer() []string {
+ return message.buffer
+}
+
+func (message *Message) Height() int {
+ return len(message.buffer)
+}
diff --git a/ui/view-main.go b/ui/view-main.go
index 0c3b0a4..36ffe28 100644
--- a/ui/view-main.go
+++ b/ui/view-main.go
@@ -162,7 +162,7 @@ func (view *MainView) HandleCommand(room, command string, args []string) {
case "/quit":
view.gmx.Stop()
case "/clearcache":
- view.config.Session.Clear()
+ view.config.Clear()
view.gmx.Stop()
case "/panic":
panic("This is a test panic.")
@@ -239,6 +239,15 @@ func (view *MainView) Focus(delegate func(p tview.Primitive)) {
}
}
+func (view *MainView) SaveAllHistory() {
+ for _, room := range view.rooms {
+ err := room.SaveHistory(view.config.HistoryDir)
+ if err != nil {
+ debug.Printf("Failed to save history of %s: %v", room.Room.GetTitle(), err)
+ }
+ }
+}
+
func (view *MainView) addRoom(index int, room string) {
roomStore := view.matrix.GetRoom(room)
@@ -254,7 +263,13 @@ func (view *MainView) addRoom(index int, room string) {
view.rooms[room] = roomView
view.roomView.AddPage(room, roomView, true, false)
roomView.UpdateUserList()
- go view.LoadInitialHistory(room)
+
+ count, err := roomView.LoadHistory(view.config.HistoryDir)
+ if err != nil {
+ debug.Printf("Failed to load history of %s: %v", roomView.Room.GetTitle(), err)
+ } else if count <= 0 {
+ go view.LoadInitialHistory(room)
+ }
}
}
@@ -377,6 +392,11 @@ func (view *MainView) LoadHistory(room string, initial bool) {
room.AddMessage(message, widget.PrependMessage)
}
}
+ err = roomView.SaveHistory(view.config.HistoryDir)
+ if err != nil {
+ debug.Printf("%Failed to save history of %s: %v", roomView.Room.GetTitle(), err)
+ }
+ view.config.Session.Save()
view.parent.Render()
}
diff --git a/ui/widget/message-view.go b/ui/widget/message-view.go
index f263350..fe906b5 100644
--- a/ui/widget/message-view.go
+++ b/ui/widget/message-view.go
@@ -17,7 +17,9 @@
package widget
import (
+ "encoding/gob"
"fmt"
+ "os"
"time"
"github.com/gdamore/tcell"
@@ -79,6 +81,45 @@ func (view *MessageView) NewMessage(id, sender, text string, timestamp time.Time
GetHashColor(sender))
}
+func (view *MessageView) SaveHistory(path string) error {
+ file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ enc := gob.NewEncoder(file)
+ err = enc.Encode(view.messages)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (view *MessageView) LoadHistory(path string) (int, error) {
+ file, err := os.OpenFile(path, os.O_RDONLY, 0600)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return 0, nil
+ }
+ return -1, err
+ }
+ defer file.Close()
+
+ dec := gob.NewDecoder(file)
+ err = dec.Decode(&view.messages)
+ if err != nil {
+ return -1, err
+ }
+
+ for _, message := range view.messages {
+ view.updateWidestSender(message.Sender)
+ }
+
+ return len(view.messages), nil
+}
+
func (view *MessageView) updateWidestSender(sender string) {
if len(sender) > view.widestSender {
view.widestSender = len(sender)
@@ -103,8 +144,12 @@ func (view *MessageView) UpdateMessageID(message *types.Message, newID string) {
}
func (view *MessageView) AddMessage(message *types.Message, direction MessageDirection) {
+ if message == nil {
+ return
+ }
+
msg, messageExists := view.messageIDs[message.ID]
- if messageExists {
+ if msg != nil && messageExists {
message.CopyTo(msg)
direction = IgnoreMessage
}
@@ -117,7 +162,7 @@ func (view *MessageView) AddMessage(message *types.Message, direction MessageDir
if direction == AppendMessage {
if view.ScrollOffset > 0 {
- view.ScrollOffset += len(message.Buffer)
+ view.ScrollOffset += message.Height()
}
view.messages = append(view.messages, message)
view.appendBuffer(message)
@@ -137,8 +182,8 @@ func (view *MessageView) appendBuffer(message *types.Message) {
}
}
- view.textBuffer = append(view.textBuffer, message.Buffer...)
- for range message.Buffer {
+ view.textBuffer = append(view.textBuffer, message.Buffer()...)
+ for range message.Buffer() {
view.metaBuffer = append(view.metaBuffer, message)
}
view.prevMsgCount++
diff --git a/ui/widget/room-view.go b/ui/widget/room-view.go
index 433d5dd..141e993 100644
--- a/ui/widget/room-view.go
+++ b/ui/widget/room-view.go
@@ -18,6 +18,7 @@ package widget
import (
"fmt"
+ "path/filepath"
"strings"
"time"
@@ -67,6 +68,18 @@ func NewRoomView(room *rooms.Room) *RoomView {
return view
}
+func (view *RoomView) logPath(dir string) string {
+ return filepath.Join(dir, fmt.Sprintf("%s.gmxlog", view.Room.ID))
+}
+
+func (view *RoomView) SaveHistory(dir string) error {
+ return view.MessageView().SaveHistory(view.logPath(dir))
+}
+
+func (view *RoomView) LoadHistory(dir string) (int, error) {
+ return view.MessageView().LoadHistory(view.logPath(dir))
+}
+
func (view *RoomView) SetTabCompleteFunc(fn func(room *RoomView, text string, cursorOffset int) string) *RoomView {
view.input.SetTabCompleteFunc(func(text string, cursorOffset int) string {
return fn(view, text, cursorOffset)