aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui
diff options
context:
space:
mode:
authorAlexander Neumann <alexander.neumann@picos-software.com>2019-04-16 18:20:56 +0200
committerAlexander Neumann <alexander.neumann@picos-software.com>2019-04-23 11:05:00 +0200
commit6de057052066c9c137131351c3f39b41a2885fc9 (patch)
treeea99f52a3ca41aac2779f4b4e16e395dfeefecb1 /ui
parentui: refactor exclude private IPs code to be closer to existing ports and preserve user edits (diff)
downloadwireguard-windows-6de057052066c9c137131351c3f39b41a2885fc9.tar.xz
wireguard-windows-6de057052066c9c137131351c3f39b41a2885fc9.zip
ui: implement log dialog; some refactoring in manage tunnels window to share some bits
Signed-off-by: Alexander Neumann <alexander.neumann@picos-software.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to '')
-rw-r--r--ui/logdialog.go174
-rw-r--r--ui/manage_tunnels.go85
-rw-r--r--ui/util.go45
3 files changed, 234 insertions, 70 deletions
diff --git a/ui/logdialog.go b/ui/logdialog.go
new file mode 100644
index 00000000..6cc176e1
--- /dev/null
+++ b/ui/logdialog.go
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+package ui
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/lxn/win"
+
+ "github.com/lxn/walk"
+ "golang.zx2c4.com/wireguard/windows/ringlogger"
+)
+
+func runLogDialog(owner walk.Form, logger *ringlogger.Ringlogger) {
+ dlg := &LogDialog{logger: logger}
+ dlg.model = newLogModel(dlg, logger)
+ defer func() {
+ dlg.model.quit <- true
+ }()
+
+ var disposables walk.Disposables
+ defer disposables.Treat()
+
+ showError := func(err error) bool {
+ if err == nil {
+ return false
+ }
+
+ walk.MsgBox(owner, "Viewing log dialog failed", err.Error(), walk.MsgBoxIconError)
+
+ return true
+ }
+
+ var err error
+
+ if dlg.Dialog, err = walk.NewDialog(owner); showError(err) {
+ return
+ }
+ disposables.Add(dlg)
+
+ dlg.SetTitle("WireGuard Log")
+ dlg.SetLayout(walk.NewVBoxLayout())
+ dlg.SetMinMaxSize(walk.Size{600, 400}, walk.Size{})
+
+ if dlg.logView, err = walk.NewTableView(dlg); showError(err) {
+ return
+ }
+ dlg.logView.SetAlternatingRowBGColor(walk.Color(win.GetSysColor(win.COLOR_BTNFACE)))
+ dlg.logView.SetLastColumnStretched(true)
+
+ stampCol := walk.NewTableViewColumn()
+ stampCol.SetName("Stamp")
+ stampCol.SetTitle("Time")
+ stampCol.SetFormat("2006-01-02 15:04:05.000")
+ stampCol.SetWidth(150)
+ dlg.logView.Columns().Add(stampCol)
+
+ msgCol := walk.NewTableViewColumn()
+ msgCol.SetName("Line")
+ msgCol.SetTitle("Log message")
+ dlg.logView.Columns().Add(msgCol)
+
+ dlg.logView.SetModel(dlg.model)
+ dlg.logView.SetCurrentIndex(len(dlg.model.items) - 1)
+
+ buttonsContainer, err := walk.NewComposite(dlg)
+ buttonsContainer.SetLayout(walk.NewHBoxLayout())
+
+ saveButton, err := walk.NewPushButton(buttonsContainer)
+ saveButton.SetText("Save")
+ saveButton.Clicked().Attach(dlg.onSaveButtonClicked)
+
+ walk.NewHSpacer(buttonsContainer)
+
+ closeButton, err := walk.NewPushButton(buttonsContainer)
+ closeButton.SetText("Close")
+ closeButton.Clicked().Attach(dlg.onCloseButtonClicked)
+
+ dlg.SetDefaultButton(closeButton)
+ dlg.SetCancelButton(closeButton)
+
+ disposables.Spare()
+
+ dlg.Run()
+}
+
+type LogDialog struct {
+ *walk.Dialog
+ logView *walk.TableView
+ logger *ringlogger.Ringlogger
+ model *logModel
+}
+
+func (dlg *LogDialog) onSaveButtonClicked() {
+ fd := walk.FileDialog{
+ Filter: "Text Files (*.txt)|*.txt|All Files (*.*)|*.*",
+ FilePath: fmt.Sprintf("wireguard-log-%s.txt", time.Now().Format("2006-01-02T150405")),
+ Title: "Export log to file",
+ }
+
+ if ok, _ := fd.ShowSave(dlg); !ok {
+ return
+ }
+
+ extensions := []string{".log", ".txt"}
+ if fd.FilterIndex < 3 && !strings.HasSuffix(fd.FilePath, extensions[fd.FilterIndex-1]) {
+ fd.FilePath = fd.FilePath + extensions[fd.FilterIndex-1]
+ }
+
+ writeFileWithOverwriteHandling(dlg, fd.FilePath, func(file *os.File) error {
+ if _, err := dlg.logger.WriteTo(file); err != nil {
+ return fmt.Errorf("exportLog: Ringlogger.WriteTo failed: %v", err)
+ }
+
+ return nil
+ })
+}
+
+func (dlg *LogDialog) onCloseButtonClicked() {
+ dlg.Accept()
+}
+
+type logModel struct {
+ walk.ReflectTableModelBase
+ dlg *LogDialog
+ quit chan bool
+ logger *ringlogger.Ringlogger
+ items []ringlogger.FollowLine
+}
+
+func newLogModel(dlg *LogDialog, logger *ringlogger.Ringlogger) *logModel {
+ mdl := &logModel{dlg: dlg, quit: make(chan bool), logger: logger}
+ mdl.items, _ = logger.FollowFromCursor(ringlogger.CursorAll)
+
+ go func() {
+ ticker := time.NewTicker(time.Second)
+
+ for {
+ select {
+ case <-ticker.C:
+ items, _ := mdl.logger.FollowFromCursor(ringlogger.CursorAll)
+
+ if len(items) > 0 && (len(mdl.items) == 0 || items[len(items)-1].Stamp.After(mdl.items[len(mdl.items)-1].Stamp)) {
+ mdl.dlg.Synchronize(func() {
+ scrollToMostRecent := mdl.dlg.logView.CurrentIndex() == len(mdl.items)-1
+
+ mdl.items = items
+ mdl.PublishRowsReset()
+
+ if scrollToMostRecent {
+ mdl.dlg.logView.SetCurrentIndex(len(mdl.items) - 1)
+ }
+ })
+ }
+
+ case <-mdl.quit:
+ ticker.Stop()
+ break
+ }
+ }
+ }()
+
+ return mdl
+}
+
+func (mdl *logModel) Items() interface{} {
+ return mdl.items
+}
diff --git a/ui/manage_tunnels.go b/ui/manage_tunnels.go
index bd94c551..353b4f68 100644
--- a/ui/manage_tunnels.go
+++ b/ui/manage_tunnels.go
@@ -100,9 +100,9 @@ func (mtw *ManageTunnelsWindow) setup() error {
addAction.SetText("Add empty tunnel")
addAction.Triggered().Attach(mtw.onAddTunnel)
- exportLogAction := walk.NewAction()
- exportLogAction.SetText("Export log to file...")
- exportLogAction.Triggered().Attach(mtw.onExportLog)
+ viewLogAction := walk.NewAction()
+ viewLogAction.SetText("View Log")
+ viewLogAction.Triggered().Attach(mtw.onViewLog)
exportTunnelsAction := walk.NewAction()
exportTunnelsAction.SetText("Export tunnels to zip...")
@@ -121,7 +121,7 @@ func (mtw *ManageTunnelsWindow) setup() error {
deleteAction.Triggered().Attach(mtw.onDelete)
settingsMenu, _ := walk.NewMenu()
- settingsMenu.Actions().Add(exportLogAction)
+ settingsMenu.Actions().Add(viewLogAction)
settingsMenu.Actions().Add(exportTunnelsAction)
settingsMenuAction, _ := tunnelsToolBar.Actions().AddMenu(settingsMenu)
settingsMenuAction.SetText("Export")
@@ -288,7 +288,7 @@ func (mtw *ManageTunnelsWindow) importFiles(paths []string) {
}
func (mtw *ManageTunnelsWindow) exportTunnels(filePath string) {
- mtw.writeFileWithOverwriteHandling(filePath, func(file *os.File) error {
+ writeFileWithOverwriteHandling(mtw, filePath, func(file *os.File) error {
writer := zip.NewWriter(file)
for _, tunnel := range mtw.tunnelsView.model.tunnels {
@@ -359,48 +359,6 @@ func (mtw *ManageTunnelsWindow) TunnelDeleted() *walk.StringEvent {
return mtw.tunnelDeletedPublisher.Event()
}
-func (mtw *ManageTunnelsWindow) exportLog(filePath string) {
- mtw.writeFileWithOverwriteHandling(filePath, func(file *os.File) error {
- if _, err := mtw.logger.WriteTo(file); err != nil {
- return fmt.Errorf("exportLog: Ringlogger.WriteTo failed: %v", err)
- }
-
- return nil
- })
-}
-
-func (mtw *ManageTunnelsWindow) writeFileWithOverwriteHandling(filePath string, write func(file *os.File) error) bool {
- showError := func(err error) bool {
- if err == nil {
- return false
- }
-
- walk.MsgBox(mtw, "Writing file failed", err.Error(), walk.MsgBoxIconError)
-
- return true
- }
-
- file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600)
- if err != nil {
- if os.IsExist(err) {
- if walk.DlgCmdNo == walk.MsgBox(mtw, "Writing file failed", fmt.Sprintf(`File "%s" already exists.
-
-Do you want to overwrite it?`, filePath), walk.MsgBoxYesNo|walk.MsgBoxDefButton2|walk.MsgBoxIconWarning) {
- return false
- }
-
- if file, err = os.Create(filePath); err != nil {
- return !showError(err)
- }
- } else {
- return !showError(err)
- }
- }
- defer file.Close()
-
- return !showError(write(file))
-}
-
// Handlers
func (mtw *ManageTunnelsWindow) onEditTunnel() {
@@ -447,10 +405,10 @@ func (mtw *ManageTunnelsWindow) onDelete() {
}
func (mtw *ManageTunnelsWindow) onImport() {
- dlg := &walk.FileDialog{}
- // dlg.InitialDirPath
- dlg.Filter = "Configuration Files (*.zip, *.conf)|*.zip;*.conf|All Files (*.*)|*.*"
- dlg.Title = "Import tunnel(s) from file..."
+ dlg := walk.FileDialog{
+ Filter: "Configuration Files (*.zip, *.conf)|*.zip;*.conf|All Files (*.*)|*.*",
+ Title: "Import tunnel(s) from file...",
+ }
if ok, _ := dlg.ShowOpenMultiple(mtw); !ok {
return
@@ -460,9 +418,10 @@ func (mtw *ManageTunnelsWindow) onImport() {
}
func (mtw *ManageTunnelsWindow) onExportTunnels() {
- dlg := &walk.FileDialog{}
- dlg.Filter = "Configuration ZIP Files (*.zip)|*.zip"
- dlg.Title = "Export tunnels to zip..."
+ dlg := walk.FileDialog{
+ Filter: "Configuration ZIP Files (*.zip)|*.zip",
+ Title: "Export tunnels to zip...",
+ }
if ok, _ := dlg.ShowSave(mtw); !ok {
return
@@ -475,20 +434,6 @@ func (mtw *ManageTunnelsWindow) onExportTunnels() {
mtw.exportTunnels(dlg.FilePath)
}
-func (mtw *ManageTunnelsWindow) onExportLog() {
- dlg := walk.FileDialog{
- Filter: "Log Files (*.log)|*.log|Text Files (*.txt)|*.txt|All Files (*.*)|*.*",
- Title: "Export log to file",
- }
-
- if ok, _ := dlg.ShowSave(mtw); !ok {
- return
- }
-
- extensions := []string{".log", ".txt"}
- if dlg.FilterIndex < 3 && !strings.HasSuffix(dlg.FilePath, extensions[dlg.FilterIndex-1]) {
- dlg.FilePath = dlg.FilePath + extensions[dlg.FilterIndex-1]
- }
-
- mtw.exportLog(dlg.FilePath)
+func (mtw *ManageTunnelsWindow) onViewLog() {
+ runLogDialog(mtw, mtw.logger)
}
diff --git a/ui/util.go b/ui/util.go
new file mode 100644
index 00000000..b17f106c
--- /dev/null
+++ b/ui/util.go
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+package ui
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/lxn/walk"
+)
+
+func writeFileWithOverwriteHandling(owner walk.Form, filePath string, write func(file *os.File) error) bool {
+ showError := func(err error) bool {
+ if err == nil {
+ return false
+ }
+
+ walk.MsgBox(owner, "Writing file failed", err.Error(), walk.MsgBoxIconError)
+
+ return true
+ }
+
+ file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600)
+ if err != nil {
+ if os.IsExist(err) {
+ if walk.DlgCmdNo == walk.MsgBox(owner, "Writing file failed", fmt.Sprintf(`File "%s" already exists.
+
+Do you want to overwrite it?`, filePath), walk.MsgBoxYesNo|walk.MsgBoxDefButton2|walk.MsgBoxIconWarning) {
+ return false
+ }
+
+ if file, err = os.Create(filePath); err != nil {
+ return !showError(err)
+ }
+ } else {
+ return !showError(err)
+ }
+ }
+ defer file.Close()
+
+ return !showError(write(file))
+}