diff options
author | Tulir Asokan <tulir@maunium.net> | 2018-03-13 15:27:12 +0200 |
---|---|---|
committer | Tulir Asokan <tulir@maunium.net> | 2018-03-13 15:27:12 +0200 |
commit | f0333df1b2b6e0ef54a580668cb759a094b56010 (patch) | |
tree | 23ab445fa74e6c164a30d99983ac233a7f8959e7 | |
parent | 2bd7315f06025047639f1e4bf6ab73048ef3f2c5 (diff) |
Add initial login view and debug panel with tview
-rw-r--r-- | .editorconfig | 12 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | config.go | 70 | ||||
-rw-r--r-- | debug.go | 56 | ||||
-rw-r--r-- | go.mod | 14 | ||||
-rw-r--r-- | gomuks.go | 113 | ||||
-rw-r--r-- | matrix.go | 118 | ||||
-rw-r--r-- | session.go | 102 |
9 files changed, 487 insertions, 1 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..21d312a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = tab +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yaml,yml}] +indent_style = space diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f11b75 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ @@ -1,2 +1,2 @@ # gomuks -A Go terminal matrix client. +A terminal Matrix client written in Go. diff --git a/config.go b/config.go new file mode 100644 index 0000000..3510e4a --- /dev/null +++ b/config.go @@ -0,0 +1,70 @@ +// 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "gopkg.in/yaml.v2" +) + +type Config struct { + MXID string `yaml:"mxid"` + HS string `yaml:"homeserver"` + + dir string `yaml:"-"` + Session *Session `yaml:"-"` +} + +func (config *Config) Load(dir string) { + config.dir = dir + os.MkdirAll(dir, 0700) + configPath := filepath.Join(dir, "config.yaml") + data, err := ioutil.ReadFile(configPath) + if err != nil { + if os.IsNotExist(err) { + return + } else { + fmt.Println("Failed to read config from", configPath) + panic(err) + } + } + + err = yaml.Unmarshal(data, &config) + if err != nil { + fmt.Println("Failed to parse config at", configPath) + panic(err) + } +} + +func (config *Config) Save() { + data, err := yaml.Marshal(&config) + if err != nil { + debug.Print("Failed to marshal config") + panic(err) + } + + path := filepath.Join(config.dir, "config.yaml") + err = ioutil.WriteFile(path, data, 0600) + if err != nil { + debug.Print("Failed to write config to", path) + panic(err) + } +} diff --git a/debug.go b/debug.go new file mode 100644 index 0000000..2533d5c --- /dev/null +++ b/debug.go @@ -0,0 +1,56 @@ +// 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "fmt" + + "github.com/rivo/tview" +) + +type DebugPane struct { + text string + pane *tview.TextView + num int +} + +func (db *DebugPane) Printf(text string, args ...interface{}) { + db.num++ + db.Write(fmt.Sprintf("[%d] %s\n", db.num, fmt.Sprintf(text, args...))) +} + +func (db *DebugPane) Print(text ...interface{}) { + db.num++ + db.Write(fmt.Sprintf("[%d] %s", db.num, fmt.Sprintln(text...))) +} + +func (db *DebugPane) Write(text string) { + if db.pane != nil { + db.text += text + db.pane.SetText(db.text) + } +} + +func (db *DebugPane) Wrap(main *tview.Pages) tview.Primitive { + db.pane = tview.NewTextView() + db.pane.SetBorder(true).SetTitle("Debug output") + db.text += "[0] Debug pane initialized\n" + db.pane.SetText(db.text) + return tview.NewGrid().SetRows(0, 20).SetColumns(0). + AddItem(main, 0, 0, 1, 1, 1, 1, true). + AddItem(db.pane, 1, 0, 1, 1, 1, 1, false) +} @@ -0,0 +1,14 @@ +module "maunium.net/go/gomuks" + +require ( + "github.com/gdamore/encoding" v0.0.0-20151215212835-b23993cbb635 + "github.com/gdamore/tcell" v1.0.0 + "github.com/jroimartin/gocui" v0.0.0-20170827195011-4f518eddb04b + "github.com/lucasb-eyer/go-colorful" v0.0.0-20170903184257-231272389856 + "github.com/matrix-org/gomatrix" v0.0.0-20171003113848-a7fc80c8060c + "github.com/mattn/go-runewidth" v0.0.2 + "github.com/nsf/termbox-go" v0.0.0-20180303152453-e2050e41c884 + "github.com/rivo/tview" v0.0.0-20180313071706-0b69b9b58142 + "golang.org/x/text" v0.0.0-20171214130843-f21a4dfb5e38 + "gopkg.in/yaml.v2" v1.1.1-gopkgin-v2.1.1 +) diff --git a/gomuks.go b/gomuks.go new file mode 100644 index 0000000..8ffc2e9 --- /dev/null +++ b/gomuks.go @@ -0,0 +1,113 @@ +// 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "os" + "path/filepath" + + "github.com/gdamore/tcell" + "github.com/rivo/tview" +) + +var matrix = new(MatrixContainer) +var config = new(Config) +var debug = new(DebugPane) + +func main() { + configDir := filepath.Join(os.Getenv("HOME"), ".config/gomuks") + os.MkdirAll(configDir, 0700) + config.Load(configDir) + + views := tview.NewPages() + InitUI(views) + + main := debug.Wrap(views) + + if len(config.MXID) > 0 { + config.LoadSession(config.MXID) + } + matrix.Init(config) + + if err := tview.NewApplication().SetRoot(main, true).Run(); err != nil { + panic(err) + } +} + +func InitUI(views *tview.Pages) { + views.AddPage("login", InitLoginUI(), true, true) +} + +func Center(width, height int, p tview.Primitive) tview.Primitive { + return tview.NewFlex(). + AddItem(tview.NewBox(), 0, 1, false). + AddItem(tview.NewFlex(). + SetDirection(tview.FlexRow). + AddItem(tview.NewBox(), 0, 1, false). + AddItem(p, height, 1, true). + AddItem(tview.NewBox(), 0, 1, false), width, 1, true). + AddItem(tview.NewBox(), 0, 1, false) +} + +type FormTextView struct { + *tview.TextView +} + +func (ftv *FormTextView) GetLabel() string { + return "" +} + +func (ftv *FormTextView) SetFormAttributes(label string, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) tview.FormItem { + return ftv +} + +func (ftv *FormTextView) GetFieldWidth() int { + _, _, w, _ := ftv.TextView.GetRect() + return w +} + +func (ftv *FormTextView) SetFinishedFunc(handler func(key tcell.Key)) tview.FormItem { + ftv.SetDoneFunc(handler) + return ftv +} + +func login(form *tview.Form) func() { + return func() { + hs := form.GetFormItem(0).(*tview.InputField).GetText() + mxid := form.GetFormItem(1).(*tview.InputField).GetText() + password := form.GetFormItem(2).(*tview.InputField).GetText() + debug.Printf("%s %s %s", hs, mxid, password) + config.HS = hs + debug.Print(matrix.Init(config)) + debug.Print(matrix.Login(mxid, password)) + } +} + +func InitLoginUI() tview.Primitive { + form := tview.NewForm().SetButtonsAlign(tview.AlignCenter) + hs := config.HS + if len(hs) == 0 { + hs = "https://matrix.org" + } + form. + AddInputField("Homeserver", hs, 30, nil, nil). + AddInputField("Username", config.MXID, 30, nil, nil). + AddPasswordField("Password", "", 30, '*', nil). + AddButton("Log in", login(form)) + form.SetBorder(true).SetTitle("Log in to Matrix") + return Center(45, 13, form) +} diff --git a/matrix.go b/matrix.go new file mode 100644 index 0000000..b559f17 --- /dev/null +++ b/matrix.go @@ -0,0 +1,118 @@ +// 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "fmt" + + "github.com/matrix-org/gomatrix" +) + +type MatrixContainer struct { + lient *gomatrix.Client + config *Config + running bool + stop chan bool +} + +func (c *MatrixContainer) Initialized() bool { + return c.lient != nil +} + +func (c *MatrixContainer) Init(config *Config) error { + c.config = config + + if c.lient != nil { + c.lient.StopSync() + } + + if len(c.config.HS) == 0 { + return fmt.Errorf("no homeserver in config") + } + + var mxid, accessToken string + if c.config.Session != nil { + accessToken = c.config.Session.AccessToken + mxid = c.config.MXID + } + + var err error + c.lient, err = gomatrix.NewClient(c.config.HS, mxid, accessToken) + if err != nil { + return err + } + + c.stop = make(chan bool, 1) + + if c.config.Session != nil { + go c.Start() + } + return nil +} + +func (c *MatrixContainer) Login(user, password string) error { + resp, err := c.lient.Login(&gomatrix.ReqLogin{ + Type: "m.login.password", + User: user, + Password: password, + }) + if err != nil { + return err + } + c.lient.SetCredentials(resp.UserID, resp.AccessToken) + c.config.MXID = resp.UserID + c.config.Save() + + c.config.Session = c.config.NewSession(resp.UserID) + c.config.Session.AccessToken = resp.AccessToken + c.config.Session.Save() + + go c.Start() + + return nil +} + +func (c *MatrixContainer) Stop() { + c.stop <- true + c.lient.StopSync() +} + +func (c *MatrixContainer) Start() { + debug.Print("Starting sync...") + c.running = true + c.lient.Store = c.config.Session + + syncer := c.lient.Syncer.(*gomatrix.DefaultSyncer) + syncer.OnEventType("m.room.message", c.HandleMessage) + + for { + select { + case <-c.stop: + debug.Print("Stopping sync...") + c.running = false + return + default: + if err := c.lient.Sync(); err != nil { + debug.Print("Sync() errored", err) + } + } + } +} + +func (c *MatrixContainer) HandleMessage(evt *gomatrix.Event) { + debug.Print("Message received") +} diff --git a/session.go b/session.go new file mode 100644 index 0000000..8f0e5d8 --- /dev/null +++ b/session.go @@ -0,0 +1,102 @@ +// 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "encoding/json" + "io/ioutil" + "path/filepath" + + "github.com/matrix-org/gomatrix" +) + +type Session struct { + MXID string `json:"-"` + path string `json:"-"` + AccessToken string + NextBatch string + FilterID string + Rooms map[string]*gomatrix.Room +} + +func (config *Config) LoadSession(mxid string) { + config.Session = config.NewSession(mxid) + config.Session.Load() +} + +func (config *Config) NewSession(mxid string) *Session { + return &Session{ + MXID: mxid, + path: filepath.Join(config.dir, mxid+".session"), + Rooms: make(map[string]*gomatrix.Room), + } +} + +func (s *Session) Load() { + data, err := ioutil.ReadFile(s.path) + if err != nil { + debug.Print("Failed to read session from", s.path) + panic(err) + } + + err = json.Unmarshal(data, s) + if err != nil { + debug.Print("Failed to parse session at", s.path) + panic(err) + } +} + +func (s *Session) Save() { + data, err := json.Marshal(s) + if err != nil { + debug.Print("Failed to marshal session of", s.MXID) + panic(err) + } + + err = ioutil.WriteFile(s.path, data, 0600) + if err != nil { + debug.Print("Failed to write session to", s.path) + panic(err) + } +} + +func (s *Session) LoadFilterID(_ string) string { + return s.FilterID +} + +func (s *Session) LoadNextBatch(_ string) string { + return s.NextBatch +} + +func (s *Session) LoadRoom(mxid string) *gomatrix.Room { + return s.Rooms[mxid] +} + +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) SaveRoom(room *gomatrix.Room) { + s.Rooms[room.ID] = room + s.Save() +} |