Refactor
Updated event management based on changes to termui
This commit is contained in:
parent
ce5342cfc9
commit
8ee8950ba2
27
README.md
27
README.md
|
@ -23,7 +23,7 @@ git clone --depth 1 https://github.com/cjbassi/gotop /tmp/gotop
|
|||
/tmp/gotop/scripts/download.sh
|
||||
```
|
||||
|
||||
Then move `gotop` into your $PATH somewhere.
|
||||
Then move `gotop` into your \$PATH somewhere.
|
||||
|
||||
### Arch Linux
|
||||
|
||||
|
@ -47,18 +47,25 @@ go get github.com/cjbassi/gotop
|
|||
### Keybinds
|
||||
|
||||
- Quit: `q` or `<C-c>`
|
||||
- Process Navigation:
|
||||
- `<up>`/`<down>` and `j`/`k`: up and down
|
||||
- `<C-d>` and `<C-u>`: up and down half a page
|
||||
- `<C-f>` and `<C-b>`: up and down a full page
|
||||
- `gg` and `G`: jump to top and bottom
|
||||
- Process Sorting:
|
||||
- Process navigation
|
||||
- `k` and `<Up>`: up
|
||||
- `j` and `<Down`: down
|
||||
- `<C-u>`: half page up
|
||||
- `<C-d>`: half page down
|
||||
- `<C-b>`: full page up
|
||||
- `<C-f>`: full page down
|
||||
- `gg` and `<Home>`: jump to top
|
||||
- `G` and `<End>`: jump to bottom
|
||||
- Process actions:
|
||||
- `<Tab>`: toggle process grouping
|
||||
- `dd`: kill selected process or group of processes
|
||||
- Process sorting
|
||||
- `c`: CPU
|
||||
- `m`: Mem
|
||||
- `p`: PID
|
||||
- `<tab>`: toggle process grouping
|
||||
- `dd`: kill the selected process or process group
|
||||
- `h` and `l`: zoom in and out of CPU and Mem graphs
|
||||
- CPU and Mem graph scaling:
|
||||
- `h`: scale in
|
||||
- `l`: scale out
|
||||
- `?`: toggles keybind help menu
|
||||
|
||||
### Mouse
|
||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module github.com/cjbassi/gotop
|
|||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd // indirect
|
||||
github.com/cjbassi/termui v0.0.0-20180823181054-5edfcb3a441f
|
||||
github.com/cjbassi/termui v0.0.0-20181129231847-3a3db079d9dd
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -4,6 +4,10 @@ github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd h1:nSJpATLVvFa
|
|||
github.com/cjbassi/drawille-go v0.0.0-20180329221028-ad535d0f92cd/go.mod h1:vjcQJUZJYD3MeVGhtZXSMnCHfUNZxsyYzJt90eCYxK4=
|
||||
github.com/cjbassi/termui v0.0.0-20180823181054-5edfcb3a441f h1:t8d9FIPBeDHClPJBkB8yJyIBcMIxzdMAY2xB1vWHi48=
|
||||
github.com/cjbassi/termui v0.0.0-20180823181054-5edfcb3a441f/go.mod h1:rqXckrwz+i0fH/zNwU6AdBNULHwmZsgehnSlhKP5i2Q=
|
||||
github.com/cjbassi/termui v0.0.0-20181129202454-e08bceac6d82 h1:Nohf7C2tEJfEtfJ2mAF244MPJUj6JT9Quzf4ZrkmEfE=
|
||||
github.com/cjbassi/termui v0.0.0-20181129202454-e08bceac6d82/go.mod h1:rqXckrwz+i0fH/zNwU6AdBNULHwmZsgehnSlhKP5i2Q=
|
||||
github.com/cjbassi/termui v0.0.0-20181129231847-3a3db079d9dd h1:12/9RCEyFB4mnNlafhySzhfPgFIfTxbjHrkhEX0SgDQ=
|
||||
github.com/cjbassi/termui v0.0.0-20181129231847-3a3db079d9dd/go.mod h1:rqXckrwz+i0fH/zNwU6AdBNULHwmZsgehnSlhKP5i2Q=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
|
||||
|
|
238
main.go
238
main.go
|
@ -21,27 +21,15 @@ import (
|
|||
var version = "1.5.1"
|
||||
|
||||
var (
|
||||
termResized = make(chan bool, 1)
|
||||
|
||||
helpToggled = make(chan bool, 1)
|
||||
helpVisible = false
|
||||
|
||||
wg sync.WaitGroup
|
||||
// used to render the proc widget whenever a key is pressed for it
|
||||
keyPressed = make(chan bool, 1)
|
||||
// used to render cpu and mem when zoom has changed
|
||||
zoomed = make(chan bool, 1)
|
||||
|
||||
colorscheme = colorschemes.Default
|
||||
|
||||
colorscheme = colorschemes.Default
|
||||
minimal = false
|
||||
widgetCount = 6
|
||||
interval = time.Second
|
||||
zoom = 7
|
||||
zoomInterval = 3
|
||||
|
||||
averageLoad = false
|
||||
percpuLoad = false
|
||||
helpVisible = false
|
||||
averageLoad = false
|
||||
percpuLoad = false
|
||||
widgetCount = 6
|
||||
|
||||
cpu *w.CPU
|
||||
mem *w.Mem
|
||||
|
@ -49,7 +37,6 @@ var (
|
|||
net *w.Net
|
||||
disk *w.Disk
|
||||
temp *w.Temp
|
||||
|
||||
help *w.HelpMenu
|
||||
)
|
||||
|
||||
|
@ -78,6 +65,8 @@ Colorschemes:
|
|||
if val, _ := args["--color"]; val != nil {
|
||||
handleColorscheme(val.(string))
|
||||
}
|
||||
averageLoad, _ = args["--averagecpu"].(bool)
|
||||
percpuLoad, _ = args["--percpu"].(bool)
|
||||
|
||||
minimal, _ = args["--minimal"].(bool)
|
||||
if minimal {
|
||||
|
@ -91,9 +80,6 @@ Colorschemes:
|
|||
} else {
|
||||
interval = time.Second / time.Duration(rate)
|
||||
}
|
||||
|
||||
averageLoad, _ = args["--averagecpu"].(bool)
|
||||
percpuLoad, _ = args["--percpu"].(bool)
|
||||
}
|
||||
|
||||
func handleColorscheme(cs string) {
|
||||
|
@ -153,41 +139,6 @@ func setupGrid() {
|
|||
}
|
||||
}
|
||||
|
||||
func keyBinds() {
|
||||
// quits
|
||||
ui.On("q", "<C-c>", func(e ui.Event) {
|
||||
ui.StopLoop()
|
||||
})
|
||||
|
||||
// toggles help menu
|
||||
ui.On("?", func(e ui.Event) {
|
||||
helpToggled <- true
|
||||
helpVisible = !helpVisible
|
||||
})
|
||||
// hides help menu
|
||||
ui.On("<escape>", func(e ui.Event) {
|
||||
if helpVisible {
|
||||
helpToggled <- true
|
||||
helpVisible = false
|
||||
}
|
||||
})
|
||||
|
||||
ui.On("h", func(e ui.Event) {
|
||||
zoom += zoomInterval
|
||||
cpu.Zoom = zoom
|
||||
mem.Zoom = zoom
|
||||
zoomed <- true
|
||||
})
|
||||
ui.On("l", func(e ui.Event) {
|
||||
if zoom > zoomInterval {
|
||||
zoom -= zoomInterval
|
||||
cpu.Zoom = zoom
|
||||
mem.Zoom = zoom
|
||||
zoomed <- true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func termuiColors() {
|
||||
ui.Theme.Fg = ui.Color(colorscheme.Fg)
|
||||
ui.Theme.Bg = ui.Color(colorscheme.Bg)
|
||||
|
@ -227,8 +178,8 @@ func widgetColors() {
|
|||
}
|
||||
}
|
||||
|
||||
// load widgets asynchronously but wait till they are all finished
|
||||
func initWidgets() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(widgetCount)
|
||||
|
||||
go func() {
|
||||
|
@ -240,7 +191,7 @@ func initWidgets() {
|
|||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
proc = w.NewProc(keyPressed)
|
||||
proc = w.NewProc()
|
||||
wg.Done()
|
||||
}()
|
||||
if !minimal {
|
||||
|
@ -261,18 +212,122 @@ func initWidgets() {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func eventLoop() {
|
||||
drawTicker := time.NewTicker(interval).C
|
||||
|
||||
// handles kill signal sent to gotop
|
||||
sigTerm := make(chan os.Signal, 2)
|
||||
signal.Notify(sigTerm, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
uiEvents := ui.PollEvents()
|
||||
|
||||
previousKey := ""
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-sigTerm:
|
||||
return
|
||||
case <-drawTicker:
|
||||
if !helpVisible {
|
||||
ui.Render(ui.Body)
|
||||
}
|
||||
case e := <-uiEvents:
|
||||
switch e.ID {
|
||||
case "q", "<C-c>":
|
||||
return
|
||||
case "?":
|
||||
helpVisible = !helpVisible
|
||||
if helpVisible {
|
||||
ui.Clear()
|
||||
ui.Render(help)
|
||||
} else {
|
||||
ui.Render(ui.Body)
|
||||
}
|
||||
case "h":
|
||||
if !helpVisible {
|
||||
zoom += zoomInterval
|
||||
cpu.Zoom = zoom
|
||||
mem.Zoom = zoom
|
||||
ui.Render(cpu, mem)
|
||||
}
|
||||
case "l":
|
||||
if !helpVisible {
|
||||
if zoom > zoomInterval {
|
||||
zoom -= zoomInterval
|
||||
cpu.Zoom = zoom
|
||||
mem.Zoom = zoom
|
||||
ui.Render(cpu, mem)
|
||||
}
|
||||
}
|
||||
case "<Escape>":
|
||||
if helpVisible {
|
||||
helpVisible = false
|
||||
ui.Render(ui.Body)
|
||||
}
|
||||
case "<Resize>":
|
||||
payload := e.Payload.(ui.Resize)
|
||||
ui.Body.Width, ui.Body.Height = payload.Width, payload.Height
|
||||
ui.Body.Resize()
|
||||
ui.Clear()
|
||||
if helpVisible {
|
||||
ui.Render(help)
|
||||
} else {
|
||||
ui.Render(ui.Body)
|
||||
}
|
||||
|
||||
case "<MouseLeft>":
|
||||
payload := e.Payload.(ui.Mouse)
|
||||
proc.Click(payload.X, payload.Y)
|
||||
ui.Render(proc)
|
||||
case "<MouseWheelUp>", "<Up>", "k":
|
||||
proc.Up()
|
||||
ui.Render(proc)
|
||||
case "<MouseWheelDown>", "<Down>", "j":
|
||||
proc.Down()
|
||||
ui.Render(proc)
|
||||
case "g", "<Home>":
|
||||
if previousKey == "g" {
|
||||
proc.Top()
|
||||
ui.Render(proc)
|
||||
previousKey = ""
|
||||
}
|
||||
case "G", "<End>":
|
||||
proc.Bottom()
|
||||
ui.Render(proc)
|
||||
case "<C-d>":
|
||||
proc.HalfPageDown()
|
||||
ui.Render(proc)
|
||||
case "<C-u>":
|
||||
proc.HalfPageUp()
|
||||
ui.Render(proc)
|
||||
case "<C-f>":
|
||||
proc.PageDown()
|
||||
ui.Render(proc)
|
||||
case "<C-b>":
|
||||
proc.PageUp()
|
||||
ui.Render(proc)
|
||||
case "d":
|
||||
if previousKey == "d" {
|
||||
proc.Kill()
|
||||
previousKey = ""
|
||||
}
|
||||
case "<Tab>":
|
||||
proc.Tab()
|
||||
ui.Render(proc)
|
||||
case "m", "c", "p":
|
||||
proc.ChangeSort(e)
|
||||
ui.Render(proc)
|
||||
}
|
||||
previousKey = e.ID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cliArguments()
|
||||
|
||||
keyBinds()
|
||||
|
||||
// need to do this before initializing widgets so that they can inherit the colors
|
||||
termuiColors()
|
||||
|
||||
termuiColors() // need to do this before initializing widgets so that they can inherit the colors
|
||||
initWidgets()
|
||||
|
||||
widgetColors()
|
||||
|
||||
help = w.NewHelpMenu()
|
||||
|
||||
// inits termui
|
||||
|
@ -283,53 +338,6 @@ func main() {
|
|||
defer ui.Close()
|
||||
|
||||
setupGrid()
|
||||
|
||||
ui.On("<resize>", func(e ui.Event) {
|
||||
ui.Body.Width, ui.Body.Height = e.Width, e.Height
|
||||
ui.Body.Resize()
|
||||
|
||||
termResized <- true
|
||||
})
|
||||
|
||||
// all rendering done here
|
||||
go func() {
|
||||
ui.Render(ui.Body)
|
||||
drawTick := time.NewTicker(interval)
|
||||
for {
|
||||
if helpVisible {
|
||||
select {
|
||||
case <-helpToggled:
|
||||
ui.Render(ui.Body)
|
||||
case <-termResized:
|
||||
ui.Clear()
|
||||
ui.Render(help)
|
||||
}
|
||||
} else {
|
||||
select {
|
||||
case <-helpToggled:
|
||||
ui.Clear()
|
||||
ui.Render(help)
|
||||
case <-termResized:
|
||||
ui.Clear()
|
||||
ui.Render(ui.Body)
|
||||
case <-keyPressed:
|
||||
ui.Render(proc)
|
||||
case <-zoomed:
|
||||
ui.Render(cpu, mem)
|
||||
case <-drawTick.C:
|
||||
ui.Render(ui.Body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// handles kill signal sent to gotop
|
||||
c := make(chan os.Signal, 2)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-c
|
||||
ui.StopLoop()
|
||||
}()
|
||||
|
||||
ui.Loop()
|
||||
ui.Render(ui.Body)
|
||||
eventLoop()
|
||||
}
|
||||
|
|
|
@ -48,10 +48,10 @@ func NewCPU(interval time.Duration, zoom int, average bool, percpu bool) *CPU {
|
|||
}
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(self.interval)
|
||||
go self.update() // update asynchronously because of 1 second blocking period
|
||||
|
||||
go func() {
|
||||
// update asynchronously because of 1 second blocking period
|
||||
go self.update()
|
||||
ticker := time.NewTicker(self.interval)
|
||||
for range ticker.C {
|
||||
self.update()
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ func NewDisk() *Disk {
|
|||
|
||||
self.update()
|
||||
|
||||
ticker := time.NewTicker(self.interval)
|
||||
go func() {
|
||||
ticker := time.NewTicker(self.interval)
|
||||
for range ticker.C {
|
||||
self.update()
|
||||
}
|
||||
|
|
|
@ -9,21 +9,28 @@ import (
|
|||
const KEYBINDS = `
|
||||
Quit: q or <C-c>
|
||||
|
||||
Process Navigation
|
||||
- <up>/<down> and j/k: up and down
|
||||
- <C-d> and <C-u>: up and down half a page
|
||||
- <C-f> and <C-b>: up and down a full page
|
||||
- gg and G: jump to top and bottom
|
||||
Process navigation
|
||||
- k and <Up>: up
|
||||
- j and <Down>: down
|
||||
- <C-u>: half page up
|
||||
- <C-d>: half page down
|
||||
- <C-b>: full page up
|
||||
- <C-f>: full page down
|
||||
- gg and <Home>: jump to top
|
||||
- G and <End>: jump to bottom
|
||||
|
||||
Process Sorting
|
||||
Process actions:
|
||||
- <Tab>: toggle process grouping
|
||||
- dd: kill selected process or group of processes
|
||||
|
||||
Process sorting
|
||||
- c: CPU
|
||||
- m: Mem
|
||||
- p: PID
|
||||
|
||||
<tab>: toggle process grouping
|
||||
dd: kill the selected process or process group
|
||||
|
||||
h and l: zoom in and out of CPU and Mem graphs
|
||||
CPU and Mem graph scaling:
|
||||
- h: scale in
|
||||
- l: scale out
|
||||
`
|
||||
|
||||
type HelpMenu struct {
|
||||
|
@ -32,8 +39,8 @@ type HelpMenu struct {
|
|||
|
||||
func NewHelpMenu() *HelpMenu {
|
||||
block := ui.NewBlock()
|
||||
block.X = 48 // width - 1
|
||||
block.Y = 17 // height - 1
|
||||
block.X = 51 // width - 1
|
||||
block.Y = 24 // height - 1
|
||||
return &HelpMenu{block}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ func NewMem(interval time.Duration, zoom int) *Mem {
|
|||
|
||||
self.update()
|
||||
|
||||
ticker := time.NewTicker(self.interval)
|
||||
go func() {
|
||||
ticker := time.NewTicker(self.interval)
|
||||
for range ticker.C {
|
||||
self.update()
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ func NewNet() *Net {
|
|||
|
||||
self.update()
|
||||
|
||||
ticker := time.NewTicker(self.interval)
|
||||
go func() {
|
||||
ticker := time.NewTicker(self.interval)
|
||||
for range ticker.C {
|
||||
self.update()
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ func (self *Net) update() {
|
|||
interfaces, _ := psNet.IOCounters(false)
|
||||
curRecvTotal := interfaces[0].BytesRecv
|
||||
curSentTotal := interfaces[0].BytesSent
|
||||
var recvRecent uint64 = 0
|
||||
var sentRecent uint64 = 0
|
||||
var recvRecent uint64
|
||||
var sentRecent uint64
|
||||
|
||||
if self.prevRecvTotal != 0 { // if this isn't the first update
|
||||
recvRecent = curRecvTotal - self.prevRecvTotal
|
||||
|
|
|
@ -34,10 +34,9 @@ type Proc struct {
|
|||
groupedProcs []Process
|
||||
ungroupedProcs []Process
|
||||
group bool
|
||||
KeyPressed chan bool
|
||||
}
|
||||
|
||||
func NewProc(keyPressed chan bool) *Proc {
|
||||
func NewProc() *Proc {
|
||||
cpuCount, _ := psCPU.Counts(false)
|
||||
self := &Proc{
|
||||
Table: ui.NewTable(),
|
||||
|
@ -45,7 +44,6 @@ func NewProc(keyPressed chan bool) *Proc {
|
|||
cpuCount: float64(cpuCount),
|
||||
sortMethod: "c",
|
||||
group: true,
|
||||
KeyPressed: keyPressed,
|
||||
}
|
||||
self.Label = "Processes"
|
||||
self.ColResizer = self.ColResize
|
||||
|
@ -58,12 +56,10 @@ func NewProc(keyPressed chan bool) *Proc {
|
|||
self.UniqueCol = 1
|
||||
}
|
||||
|
||||
self.keyBinds()
|
||||
|
||||
self.update()
|
||||
|
||||
ticker := time.NewTicker(self.interval)
|
||||
go func() {
|
||||
ticker := time.NewTicker(self.interval)
|
||||
for range ticker.C {
|
||||
self.update()
|
||||
}
|
||||
|
@ -112,83 +108,23 @@ func (self *Proc) ColResize() {
|
|||
}
|
||||
}
|
||||
|
||||
func (self *Proc) keyBinds() {
|
||||
ui.On("<MouseLeft>", func(e ui.Event) {
|
||||
self.Click(e.MouseX, e.MouseY)
|
||||
self.KeyPressed <- true
|
||||
})
|
||||
|
||||
ui.On("<MouseWheelUp>", "<MouseWheelDown>", func(e ui.Event) {
|
||||
switch e.Key {
|
||||
case "<MouseWheelDown>":
|
||||
self.Down()
|
||||
case "<MouseWheelUp>":
|
||||
self.Up()
|
||||
}
|
||||
self.KeyPressed <- true
|
||||
})
|
||||
|
||||
ui.On("<up>", "<down>", func(e ui.Event) {
|
||||
switch e.Key {
|
||||
case "<up>":
|
||||
self.Up()
|
||||
case "<down>":
|
||||
self.Down()
|
||||
}
|
||||
self.KeyPressed <- true
|
||||
})
|
||||
|
||||
viKeys := []string{"j", "k", "gg", "G", "<C-d>", "<C-u>", "<C-f>", "<C-b>", "<home>", "<end>"}
|
||||
ui.On(viKeys, func(e ui.Event) {
|
||||
switch e.Key {
|
||||
case "j":
|
||||
self.Down()
|
||||
case "k":
|
||||
self.Up()
|
||||
case "<home>":
|
||||
fallthrough
|
||||
case "gg":
|
||||
self.Top()
|
||||
case "<end>":
|
||||
fallthrough
|
||||
case "G":
|
||||
self.Bottom()
|
||||
case "<C-d>":
|
||||
self.HalfPageDown()
|
||||
case "<C-u>":
|
||||
self.HalfPageUp()
|
||||
case "<C-f>":
|
||||
self.PageDown()
|
||||
case "<C-b>":
|
||||
self.PageUp()
|
||||
}
|
||||
self.KeyPressed <- true
|
||||
})
|
||||
|
||||
ui.On("dd", func(e ui.Event) {
|
||||
self.Kill()
|
||||
})
|
||||
|
||||
ui.On("<tab>", func(e ui.Event) {
|
||||
self.group = !self.group
|
||||
if self.group {
|
||||
self.UniqueCol = 1
|
||||
} else {
|
||||
self.UniqueCol = 0
|
||||
}
|
||||
self.Sort()
|
||||
func (self *Proc) ChangeSort(e ui.Event) {
|
||||
if self.sortMethod != e.ID {
|
||||
self.sortMethod = e.ID
|
||||
self.Top()
|
||||
self.KeyPressed <- true
|
||||
})
|
||||
self.Sort()
|
||||
}
|
||||
}
|
||||
|
||||
ui.On("m", "c", "p", func(e ui.Event) {
|
||||
if self.sortMethod != e.Key {
|
||||
self.sortMethod = e.Key
|
||||
self.Top()
|
||||
self.Sort()
|
||||
self.KeyPressed <- true
|
||||
}
|
||||
})
|
||||
func (self *Proc) Tab() {
|
||||
self.group = !self.group
|
||||
if self.group {
|
||||
self.UniqueCol = 1
|
||||
} else {
|
||||
self.UniqueCol = 0
|
||||
}
|
||||
self.Sort()
|
||||
self.Top()
|
||||
}
|
||||
|
||||
// Group groupes a []Process based on command name.
|
||||
|
|
|
@ -31,8 +31,8 @@ func NewTemp() *Temp {
|
|||
|
||||
self.update()
|
||||
|
||||
ticker := time.NewTicker(self.interval)
|
||||
go func() {
|
||||
ticker := time.NewTicker(self.interval)
|
||||
for range ticker.C {
|
||||
self.update()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user