Skip to content

Commit

Permalink
Set the refresh rate of the monitor widget
Browse files Browse the repository at this point in the history
By default refresh rate is set to 500 ms, but it can now be changed by
the user. refs #87.
  • Loading branch information
moncho committed Feb 3, 2019
1 parent 8ebf21d commit c797b28
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 8 deletions.
2 changes: 1 addition & 1 deletion app/help_texts.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const (
"<b>[m]:<darkgrey>Monitor mode</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</> <b>[Enter]:<darkgrey>Commands</></>"

monitorMapping = commonMappings +
"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</>"
"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</> <blue>|</> <b>[s]:<darkgrey>Set refresh rate</></>"

swarmMapping = commonMappings +
"<b>[m]:<darkgrey>Monitor mode</> <b>[1]:<darkgrey>Containers</> <b>[2]:<darkgrey>Images</> <b>[3]:<darkgrey>Networks</> <b>[4]:<darkgrey>Nodes</> <b>[5]:<darkgrey>Services</> <b>[6]:<darkgrey>Stacks</>"
Expand Down
51 changes: 49 additions & 2 deletions app/monitor_events.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package app

import (
"errors"
"fmt"
"github.com/moncho/dry/appui"
"github.com/moncho/dry/ui"
termbox "github.com/nsf/termbox-go"
"strconv"
)

type monitorScreenEventHandler struct {
Expand Down Expand Up @@ -52,8 +56,39 @@ func (h *monitorScreenEventHandler) handle(event termbox.Event, f func(eventHand
handled = true
cursor.Bottom()
h.widget.OnEvent(nil)
default:
handled = false
case 's': // Set the delay between updates to <delay> seconds.
handled = true
h.widget.Unmount()
prompt := appui.NewPrompt("Set the delay between updates (in milliseconds)")
widgets.add(prompt)
forwarder := newEventForwarder()
f(forwarder)
h.dry.ViewMode(NoView)
refreshScreen()
go func() {
defer h.widget.Mount()
defer h.dry.ViewMode(Monitor)
defer f(h)
events := ui.EventSource{
Events: forwarder.events(),
EventHandledCallback: func(e termbox.Event) error {
return refreshScreen()
},
}
prompt.OnFocus(events)
input, cancel := prompt.Text()
widgets.remove(prompt)
if cancel {
return
}
refreshRate, err := toInt(input)
if err != nil {
h.dry.appmessage(
fmt.Sprintf("Error setting refresh rate: %s", err.Error()))
return
}
h.widget.RefreshRate(refreshRate)
}()
}
}
if !handled {
Expand All @@ -67,3 +102,15 @@ func (h *monitorScreenEventHandler) handle(event termbox.Event, f func(eventHand
h.baseEventHandler.handle(event, nh)
}
}

func toInt(s string) (int, error) {
i, err := strconv.Atoi(s)

if err != nil {
return -1, errors.New("Be nice, a number is expected")
}
if i < 0 {
return -1, errors.New("Negative values are not allowed")
}
return i, nil
}
30 changes: 25 additions & 5 deletions appui/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package appui

import (
"context"
"strconv"
"sync"
"time"

Expand All @@ -10,6 +11,8 @@ import (
"github.com/moncho/dry/ui"
)

var defaultRefreshRate time.Duration = 500 * time.Millisecond

//Monitor is a self-refreshing ui component that shows monitoring information about docker
//containers.
type Monitor struct {
Expand All @@ -23,6 +26,7 @@ type Monitor struct {
x, y int
height, width int
startIndex, endIndex int
refreshRate time.Duration
sync.RWMutex
}

Expand All @@ -40,21 +44,26 @@ func NewMonitor(daemon docker.ContainerDaemon, y int) *Monitor {
height: height,
width: ui.ActiveScreen.Dimensions.Width,
unmount: make(chan struct{}),
refreshRate: defaultRefreshRate,
}
return &m
}

//Buffer returns the content of this monitor as a termui.Buffer
func (m *Monitor) Buffer() gizaktermui.Buffer {
m.Lock()
defer m.Unlock()
m.RLock()
defer m.RUnlock()
y := m.y
buf := gizaktermui.NewBuffer()
widgetHeader := NewWidgetHeader()
widgetHeader.HeaderEntry("Running Containers", strconv.Itoa(m.RowCount()))
widgetHeader.HeaderEntry("Refresh rate", m.refreshRate.String())

widgetHeader := WidgetHeader("Containers", m.RowCount(), "")
widgetHeader.Y = y
buf.Merge(widgetHeader.Buffer())
y += widgetHeader.Height
y += widgetHeader.GetHeight()
//Empty line between the header and the rest of the content
y++

m.header.SetY(y)
buf.Merge(m.header.Buffer())
Expand All @@ -78,6 +87,8 @@ func (m *Monitor) Filter(filter string) {

//Mount prepares this widget for rendering
func (m *Monitor) Mount() error {
m.Lock()
defer m.Unlock()
daemon := m.daemon
containers := daemon.Containers(
[]docker.ContainerFilter{docker.ContainerFilters.Running()}, docker.SortByName)
Expand Down Expand Up @@ -110,11 +121,20 @@ func (m *Monitor) OnEvent(event EventCommand) error {
return nil
}

//RefreshRate sets the refresh rate of this monitor to the given amount in
//milliseconds.
func (m *Monitor) RefreshRate(millis int) {
m.Lock()
defer m.Unlock()
m.refreshRate = time.Duration(millis) * time.Millisecond
}

//RenderLoop makes this monitor to render itself until stopped.
func (m *Monitor) RenderLoop(ctx context.Context) {

go func() {
refreshTimer := time.NewTicker(500 * time.Millisecond)
m.refresh()
refreshTimer := time.NewTicker(m.refreshRate)
defer refreshTimer.Stop()
defer func() {
for _, c := range m.openChannels {
Expand Down

0 comments on commit c797b28

Please sign in to comment.