From 702a75a8c0355737e3e62735b59fe30bee7e42f4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 22 Mar 2018 19:51:20 +0200 Subject: Save history to disk. Fixes #1 --- ui/types/message.go | 16 ++++++++++---- ui/view-main.go | 24 +++++++++++++++++++-- ui/widget/message-view.go | 53 +++++++++++++++++++++++++++++++++++++++++++---- ui/widget/room-view.go | 13 ++++++++++++ 4 files changed, 96 insertions(+), 10 deletions(-) (limited to 'ui') 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) -- cgit v1.2.3