aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/session.go3
-rw-r--r--gomuks.go9
-rw-r--r--interface/ui.go2
-rw-r--r--matrix/matrix.go57
-rw-r--r--matrix/rooms/room.go10
-rw-r--r--matrix/sync.go31
-rw-r--r--ui/message-view.go6
-rw-r--r--ui/messages/textbase.go14
-rw-r--r--ui/room-list.go57
-rw-r--r--ui/view-main.go29
10 files changed, 134 insertions, 84 deletions
diff --git a/config/session.go b/config/session.go
index 9419038..d23c778 100644
--- a/config/session.go
+++ b/config/session.go
@@ -35,6 +35,8 @@ type Session struct {
FilterID string
Rooms map[string]*rooms.Room
PushRules *pushrules.PushRuleset
+
+ InitialSyncDone bool
}
func (config *Config) LoadSession(mxid string) error {
@@ -59,6 +61,7 @@ func (s *Session) Clear() {
s.PushRules = nil
s.NextBatch = ""
s.FilterID = ""
+ s.InitialSyncDone = false
s.Save()
}
diff --git a/gomuks.go b/gomuks.go
index ffdfad3..5f5d74b 100644
--- a/gomuks.go
+++ b/gomuks.go
@@ -18,7 +18,9 @@ package main
import (
"os"
+ "os/signal"
"path/filepath"
+ "syscall"
"time"
"maunium.net/go/gomuks/config"
@@ -104,6 +106,13 @@ func (gmx *Gomuks) Stop() {
func (gmx *Gomuks) Start() {
_ = gmx.matrix.InitClient()
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+ go func() {
+ <-c
+ gmx.Stop()
+ }()
+
go gmx.StartAutosave()
if err := gmx.ui.Start(); err != nil {
panic(err)
diff --git a/interface/ui.go b/interface/ui.go
index c36819a..baa34bc 100644
--- a/interface/ui.go
+++ b/interface/ui.go
@@ -51,7 +51,7 @@ type MainView interface {
GetRoom(roomID string) RoomView
AddRoom(roomID string)
RemoveRoom(roomID string)
- SetRooms(roomIDs []string)
+ SetRooms(rooms map[string]*rooms.Room)
SaveAllHistory()
UpdateTags(room *rooms.Room, newTags []rooms.RoomTag)
diff --git a/matrix/matrix.go b/matrix/matrix.go
index d58ce20..2e97ef4 100644
--- a/matrix/matrix.go
+++ b/matrix/matrix.go
@@ -129,6 +129,7 @@ func (c *Container) Login(user, password string) error {
// Stop stops the Matrix syncer.
func (c *Container) Stop() {
if c.running {
+ debug.Print("Stopping Matrix container...")
c.stop <- true
c.client.StopSync()
}
@@ -157,22 +158,6 @@ func (c *Container) PushRules() *pushrules.PushRuleset {
return c.config.Session.PushRules
}
-// UpdateRoomList fetches the list of rooms the user has joined and sends them to the UI.
-func (c *Container) UpdateRoomList() {
- resp, err := c.client.JoinedRooms()
- if err != nil {
- respErr, _ := err.(gomatrix.HTTPError).WrappedError.(gomatrix.RespError)
- if respErr.ErrCode == "M_UNKNOWN_TOKEN" {
- c.OnLogout()
- return
- }
- debug.Print("Error fetching room list:", err)
- return
- }
-
- c.ui.MainView().SetRooms(resp.JoinedRooms)
-}
-
// OnLogout stops the syncer and moves the UI back to the login view.
func (c *Container) OnLogout() {
c.Stop()
@@ -183,15 +168,23 @@ func (c *Container) OnLogout() {
func (c *Container) OnLogin() {
c.client.Store = c.config.Session
+ debug.Print("Initializing syncer")
c.syncer = NewGomuksSyncer(c.config.Session)
c.syncer.OnEventType("m.room.message", c.HandleMessage)
c.syncer.OnEventType("m.room.member", c.HandleMembership)
c.syncer.OnEventType("m.typing", c.HandleTyping)
c.syncer.OnEventType("m.push_rules", c.HandlePushRules)
c.syncer.OnEventType("m.tag", c.HandleTag)
+ c.syncer.InitDoneCallback = func() {
+ c.config.Session.InitialSyncDone = true
+ c.ui.Render()
+ }
c.client.Syncer = c.syncer
- c.UpdateRoomList()
+ debug.Print("Setting existing rooms")
+ c.ui.MainView().SetRooms(c.config.Session.Rooms)
+
+ debug.Print("OnLogin() done.")
}
// Start moves the UI to the main view, calls OnLogin() and runs the syncer forever until stopped with Stop()
@@ -226,19 +219,23 @@ func (c *Container) Start() {
// HandleMessage is the event handler for the m.room.message timeline event.
func (c *Container) HandleMessage(evt *gomatrix.Event) {
mainView := c.ui.MainView()
+
roomView := mainView.GetRoom(evt.RoomID)
if roomView == nil {
+ debug.Printf("Failed to handle event %v: No room view found.", evt)
return
}
message := mainView.ParseEvent(roomView, evt)
if message != nil {
+ roomView.AddMessage(message, ifc.AppendMessage)
if c.syncer.FirstSyncDone {
pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should()
mainView.NotifyMessage(roomView.MxRoom(), message, pushRules)
+ c.ui.Render()
}
- roomView.AddMessage(message, ifc.AppendMessage)
- c.ui.Render()
+ } else {
+ debug.Printf("Parsing event %v failed (ParseEvent() returned nil).", evt)
}
}
@@ -279,6 +276,7 @@ func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
if evt.Unsigned.PrevContent != nil {
prevMembership, _ = evt.Unsigned.PrevContent["membership"].(string)
}
+ debug.Printf("Processing own membership change: %s->%s in %s", prevMembership, membership, evt.RoomID)
if membership == prevMembership {
return
}
@@ -287,6 +285,9 @@ func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
c.ui.MainView().AddRoom(evt.RoomID)
case "leave":
c.ui.MainView().RemoveRoom(evt.RoomID)
+ case "invite":
+ // TODO handle
+ debug.Printf("%s invited the user to %s", evt.Sender, evt.RoomID)
}
}
@@ -296,6 +297,11 @@ func (c *Container) HandleMembership(evt *gomatrix.Event) {
c.processOwnMembershipChange(evt)
}
+ if !c.config.Session.InitialSyncDone /*&& evt.Timestamp < time.Now().Add(-1*time.Hour).Unix()*/ {
+ // We don't care about other users' membership events in the initial sync.
+ return
+ }
+
mainView := c.ui.MainView()
roomView := mainView.GetRoom(evt.RoomID)
if roomView == nil {
@@ -305,16 +311,17 @@ func (c *Container) HandleMembership(evt *gomatrix.Event) {
message := mainView.ParseEvent(roomView, evt)
if message != nil {
// TODO this shouldn't be necessary
- roomView.MxRoom().UpdateState(evt)
+ //roomView.MxRoom().UpdateState(evt)
// TODO This should probably also be in a different place
- roomView.UpdateUserList()
+ //roomView.UpdateUserList()
+ roomView.AddMessage(message, ifc.AppendMessage)
+ // We don't want notifications at startup.
if c.syncer.FirstSyncDone {
pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should()
mainView.NotifyMessage(roomView.MxRoom(), message, pushRules)
+ c.ui.Render()
}
- roomView.AddMessage(message, ifc.AppendMessage)
- c.ui.Render()
}
}
@@ -471,12 +478,12 @@ func (c *Container) GetHistory(roomID, prevBatch string, limit int) ([]gomatrix.
func (c *Container) GetRoom(roomID string) *rooms.Room {
room := c.config.Session.GetRoom(roomID)
if room != nil && len(room.State) == 0 {
- events := c.getState(room.ID)
+ /*events := c.getState(room.ID)
if events != nil {
for _, event := range events {
room.UpdateState(event)
}
- }
+ }*/
}
return room
}
diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go
index 44a386b..95349c3 100644
--- a/matrix/rooms/room.go
+++ b/matrix/rooms/room.go
@@ -23,6 +23,7 @@ import (
"time"
"maunium.net/go/gomatrix"
+ "maunium.net/go/gomuks/debug"
)
type RoomNameSource int
@@ -148,6 +149,15 @@ func (room *Room) UpdateState(event *gomatrix.Event) {
case "m.room.topic":
room.topicCache = ""
}
+
+ stateKey := ""
+ if event.StateKey != nil {
+ stateKey = *event.StateKey
+ }
+ if event.Type != "m.room.member" {
+ debug.Printf("Updating state %s#%s for %s", event.Type, stateKey, room.ID)
+ }
+
if event.StateKey == nil {
room.State[event.Type][""] = event
} else {
diff --git a/matrix/sync.go b/matrix/sync.go
index f3966cb..8ad7ad5 100644
--- a/matrix/sync.go
+++ b/matrix/sync.go
@@ -20,8 +20,6 @@ package matrix
import (
"encoding/json"
- "fmt"
- "runtime/debug"
"time"
"maunium.net/go/gomatrix"
@@ -37,9 +35,10 @@ type SyncerSession interface {
// replace parts of this default syncer (e.g. the ProcessResponse method). The default syncer uses the observer
// pattern to notify callers about incoming events. See GomuksSyncer.OnEventType for more information.
type GomuksSyncer struct {
- Session SyncerSession
- listeners map[string][]gomatrix.OnEventListener // event type to listeners array
- FirstSyncDone bool
+ Session SyncerSession
+ listeners map[string][]gomatrix.OnEventListener // event type to listeners array
+ FirstSyncDone bool
+ InitDoneCallback func()
}
// NewGomuksSyncer returns an instantiated GomuksSyncer
@@ -53,17 +52,6 @@ func NewGomuksSyncer(session SyncerSession) *GomuksSyncer {
// ProcessResponse processes a Matrix sync response.
func (s *GomuksSyncer) ProcessResponse(res *gomatrix.RespSync, since string) (err error) {
- if len(since) == 0 {
- return
- }
- // debug.Print("Processing sync response", since, res)
-
- defer func() {
- if r := recover(); r != nil {
- err = fmt.Errorf("ProcessResponse for %s since %s panicked: %s\n%s", s.Session.GetUserID(), since, r, debug.Stack())
- }
- }()
-
s.processSyncEvents(nil, res.Presence.Events, false, false)
s.processSyncEvents(nil, res.AccountData.Events, false, false)
@@ -93,6 +81,9 @@ func (s *GomuksSyncer) ProcessResponse(res *gomatrix.RespSync, since string) (er
}
}
+ if since == "" && s.InitDoneCallback != nil {
+ s.InitDoneCallback()
+ }
s.FirstSyncDone = true
return
@@ -147,7 +138,13 @@ func (s *GomuksSyncer) GetFilterJSON(userID string) json.RawMessage {
"room": {
"include_leave": true,
"state": {
- "types": ["m.room.member"]
+ "types": [
+ "m.room.member",
+ "m.room.name",
+ "m.room.topic",
+ "m.room.canonical_alias",
+ "m.room.aliases"
+ ]
},
"timeline": {
"types": ["m.room.message"],
diff --git a/ui/message-view.go b/ui/message-view.go
index ca03e73..f2fb72f 100644
--- a/ui/message-view.go
+++ b/ui/message-view.go
@@ -183,7 +183,8 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.Messag
} else if oldMsg != nil {
view.replaceBuffer(oldMsg, message)
} else {
- view.replaceBuffer(message, message)
+ debug.Print("Unexpected AddMessage() call: Direction is not append or prepend, but message is new.")
+ debug.PrintStack()
}
view.messageIDs[message.ID()] = message
@@ -232,7 +233,8 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
}
if start == -1 {
- debug.Print("Called replaceBuffer() with message that was not in the buffer:", original)
+ debug.Print("Called replaceBuffer() with message that was not in the buffer:", original.ID())
+ debug.PrintStack()
view.appendBuffer(new)
return
}
diff --git a/ui/messages/textbase.go b/ui/messages/textbase.go
index 0960a57..f44d5d5 100644
--- a/ui/messages/textbase.go
+++ b/ui/messages/textbase.go
@@ -72,8 +72,18 @@ func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width
}
matches := boundaryPattern.FindAllStringIndex(extract.String(), -1)
- if len(matches) > 0 {
- extract = extract[:matches[len(matches)-1][1]]
+ if len(matches) == 0 {
+ continue
+ }
+
+ match := matches[len(matches)-1]
+ if len(match) < 2 {
+ continue
+ }
+
+ until := match[1]
+ if until < len(extract) {
+ extract = extract[:until]
}
}
msg.buffer = append(msg.buffer, extract)
diff --git a/ui/room-list.go b/ui/room-list.go
index a70fd68..9444313 100644
--- a/ui/room-list.go
+++ b/ui/room-list.go
@@ -23,6 +23,7 @@ import (
"strings"
"time"
+ "maunium.net/go/gomuks/debug"
"maunium.net/go/gomuks/matrix/rooms"
"maunium.net/go/gomuks/ui/widget"
"maunium.net/go/tcell"
@@ -57,6 +58,7 @@ func NewRoomList() *RoomList {
return &RoomList{
Box: tview.NewBox(),
items: make(map[string][]*rooms.Room),
+ tags: []string{"m.favourite", "im.vector.fake.direct", "", "m.lowpriority"},
mainTextColor: tcell.ColorWhite,
selectedTextColor: tcell.ColorWhite,
@@ -86,16 +88,17 @@ func (list *RoomList) CheckTag(tag string) {
items, ok := list.items[tag]
- if len(items) == 0 {
+ if ok && len(items) == 0 {
delete(list.items, tag)
ok = false
}
if ok && index == -1 {
list.tags = append(list.tags, tag)
- } else if index != -1 {
+ } /* TODO this doesn't work properly
+ else if index != -1 {
list.tags = append(list.tags[0:index], list.tags[index+1:]...)
- }
+ }*/
}
func (list *RoomList) AddToTag(tag string, room *rooms.Room) {
@@ -210,7 +213,8 @@ func (list *RoomList) Clear() {
func (list *RoomList) SetSelected(tag string, room *rooms.Room) {
list.selected = room
- list.selectedTag = ""
+ list.selectedTag = tag
+ debug.Print("Selecting", room.GetTitle(), "in", tag)
}
func (list *RoomList) HasSelected() bool {
@@ -229,7 +233,7 @@ func (list *RoomList) First() (string, *rooms.Room) {
for _, tag := range list.tags {
items := list.items[tag]
if len(items) > 0 {
- return tag, items[0]
+ return tag, items[len(items)-1]
}
}
return "", nil
@@ -240,7 +244,7 @@ func (list *RoomList) Last() (string, *rooms.Room) {
tag := list.tags[tagIndex]
items := list.items[tag]
if len(items) > 0 {
- return tag, items[len(items)-1]
+ return tag, items[0]
}
}
return "", nil
@@ -264,17 +268,19 @@ func (list *RoomList) Previous() (string, *rooms.Room) {
items := list.items[list.selectedTag]
index := list.indexInTag(list.selectedTag, list.selected)
- if index == len(items)-1 {
+ if index == -1 {
+ return list.First()
+ } else if index == len(items)-1 {
tagIndex := list.IndexTag(list.selectedTag)
- tagIndex++
- for ; tagIndex < len(list.tags); tagIndex++ {
- nextTag := list.tags[tagIndex]
- nextTagItems := list.items[nextTag]
- if len(nextTagItems) > 0 {
- return nextTag, nextTagItems[0]
+ tagIndex--
+ for ; tagIndex >= 0; tagIndex-- {
+ prevTag := list.tags[tagIndex]
+ prevTagItems := list.items[prevTag]
+ if len(prevTagItems) > 0 {
+ return prevTag, prevTagItems[0]
}
}
- return list.First()
+ return list.Last()
}
return list.selectedTag, items[index+1]
}
@@ -288,17 +294,19 @@ func (list *RoomList) Next() (string, *rooms.Room) {
items := list.items[list.selectedTag]
index := list.indexInTag(list.selectedTag, list.selected)
- if index == 0 {
+ if index == -1 {
+ return list.Last()
+ } else if index == 0 {
tagIndex := list.IndexTag(list.selectedTag)
- tagIndex--
- for ; tagIndex >= 0; tagIndex-- {
- prevTag := list.tags[tagIndex]
- prevTagItems := list.items[prevTag]
- if len(prevTagItems) > 0 {
- return prevTag, prevTagItems[len(prevTagItems)-1]
+ tagIndex++
+ for ; tagIndex < len(list.tags); tagIndex++ {
+ nextTag := list.tags[tagIndex]
+ nextTagItems := list.items[nextTag]
+ if len(nextTagItems) > 0 {
+ return nextTag, nextTagItems[len(nextTagItems)-1]
}
}
- return list.Last()
+ return list.First()
}
return list.selectedTag, items[index-1]
}
@@ -332,6 +340,8 @@ func (list *RoomList) Get(n int) (string, *rooms.Room) {
// Tag items
n -= len(items)
+ // Tag footer
+ n--
}
return "", nil
}
@@ -346,6 +356,8 @@ func (list *RoomList) GetTagDisplayName(tag string) string {
return "Favorites"
case tag == "m.lowpriority":
return "Low Priority"
+ case tag == "im.vector.fake.direct":
+ return "People"
case strings.HasPrefix(tag, "m."):
return strings.Title(strings.Replace(tag[len("m."):], "_", " ", -1))
case strings.HasPrefix(tag, "u."):
@@ -420,5 +432,6 @@ func (list *RoomList) Draw(screen tcell.Screen) {
break
}
}
+ y++
}
}
diff --git a/ui/view-main.go b/ui/view-main.go
index ba3a55b..d20fed3 100644
--- a/ui/view-main.go
+++ b/ui/view-main.go
@@ -173,7 +173,7 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
msgView := roomView.MessageView()
if msgView.IsAtTop() && (k == tcell.KeyPgUp || k == tcell.KeyUp) {
- go view.LoadHistory(roomView.Room.ID, false)
+ go view.LoadHistory(roomView.Room.ID)
}
switch k {
@@ -215,7 +215,7 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
switch event.Buttons() {
case tcell.WheelUp:
if msgView.IsAtTop() {
- go view.LoadHistory(roomView.Room.ID, false)
+ go view.LoadHistory(roomView.Room.ID)
} else {
msgView.AddScrollOffset(WheelScrollOffsetDiff)
@@ -293,11 +293,9 @@ func (view *MainView) addRoomPage(room *rooms.Room) {
view.roomView.AddPage(room.ID, roomView, true, false)
roomView.UpdateUserList()
- count, err := roomView.LoadHistory(view.matrix, view.config.HistoryDir)
+ _, err := roomView.LoadHistory(view.matrix, 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.LoadHistory(room.ID, true)
}
}
}
@@ -314,18 +312,25 @@ func (view *MainView) GetRoom(roomID string) ifc.RoomView {
func (view *MainView) AddRoom(roomID string) {
if view.roomList.Contains(roomID) {
+ debug.Print("Add aborted", roomID)
return
}
+ debug.Print("Adding", roomID)
room := view.matrix.GetRoom(roomID)
view.roomList.Add(room)
view.addRoomPage(room)
+ if !view.roomList.HasSelected() {
+ view.SwitchRoom(view.roomList.First())
+ }
}
func (view *MainView) RemoveRoom(roomID string) {
roomView := view.GetRoom(roomID)
if roomView == nil {
+ debug.Print("Remove aborted", roomID)
return
}
+ debug.Print("Removing", roomID)
view.roomList.Remove(roomView.MxRoom())
view.SwitchRoom(view.roomList.Selected())
@@ -336,12 +341,11 @@ func (view *MainView) RemoveRoom(roomID string) {
view.parent.Render()
}
-func (view *MainView) SetRooms(roomIDs []string) {
+func (view *MainView) SetRooms(rooms map[string]*rooms.Room) {
view.roomList.Clear()
view.roomView.Clear()
view.rooms = make(map[string]*RoomView)
- for _, roomID := range roomIDs {
- room := view.matrix.GetRoom(roomID)
+ for _, room := range rooms {
view.roomList.Add(room)
view.addRoomPage(room)
}
@@ -425,7 +429,7 @@ func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, shoul
view.roomList.Bump(room)
}
-func (view *MainView) LoadHistory(room string, initial bool) {
+func (view *MainView) LoadHistory(room string) {
defer debug.Recover()
roomView := view.rooms[room]
@@ -446,12 +450,7 @@ func (view *MainView) LoadHistory(room string, initial bool) {
return
}
- if initial {
- batch = view.config.Session.NextBatch
- debug.Print("Loading initial history for", room)
- } else {
- debug.Print("Loading more history for", room, "starting from", batch)
- }
+ debug.Print("Fetching history for", room, "starting from", batch)
history, prevBatch, err := view.matrix.GetHistory(roomView.Room.ID, batch, 50)
if err != nil {
roomView.AddServiceMessage("Failed to fetch history")