summaryrefslogtreecommitdiffstats
path: root/src/widgets/disk.go
blob: 94bbaba82460c99d3375df0f0f0b0f635f48c97c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package widgets

import (
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/cjbassi/gotop/src/utils"
	ui "github.com/cjbassi/termui"
	psDisk "github.com/shirou/gopsutil/disk"
)

type Partition struct {
	Device      string
	Mount       string
	TotalRead   uint64
	TotalWrite  uint64
	CurRead     string
	CurWrite    string
	UsedPercent int
	Free        string
}

type Disk struct {
	*ui.Table
	interval   time.Duration
	Partitions map[string]*Partition
}

func NewDisk() *Disk {
	self := &Disk{
		Table:      ui.NewTable(),
		interval:   time.Second,
		Partitions: make(map[string]*Partition),
	}
	self.Label = "Disk Usage"
	self.Header = []string{"Disk", "Mount", "Used", "Free", "R/s", "W/s"}
	self.Gap = 2
	self.ColResizer = self.ColResize

	self.update()

	ticker := time.NewTicker(self.interval)
	go func() {
		for range ticker.C {
			self.update()
		}
	}()

	return self
}

func (self *Disk) update() {
	Partitions, _ := psDisk.Partitions(false)

	// add partition if it's new
	for _, Part := range Partitions {
		device := strings.Replace(Part.Device, "/dev/", "", -1)
		if _, ok := self.Partitions[device]; !ok {
			self.Partitions[device] = &Partition{
				Device: device,
				Mount:  Part.Mountpoint,
			}
		}
	}

	// delete a partition if it no longer exists
	todelete := []string{}
	for key, _ := range self.Partitions {
		exists := false
		for _, Part := range Partitions {
			device := strings.Replace(Part.Device, "/dev/", "", -1)
			if key == device {
				exists = true
				break
			}
		}
		if !exists {
			todelete = append(todelete, key)
		}
	}
	for _, val := range todelete {
		delete(self.Partitions, val)
	}

	// updates partition info
	for _, Part := range self.Partitions {
		usage, _ := psDisk.Usage(Part.Mount)
		Part.UsedPercent = int(usage.UsedPercent)

		Free, Mag := utils.ConvertBytes(usage.Free)
		Part.Free = fmt.Sprintf("%3d%s", uint64(Free), Mag)

		ret, _ := psDisk.IOCounters("/dev/" + Part.Device)
		data := ret[Part.Device]
		curRead, curWrite := data.ReadBytes, data.WriteBytes
		if Part.TotalRead != 0 { // if this isn't the first update
			readRecent := curRead - Part.TotalRead
			writeRecent := curWrite - Part.TotalWrite

			readFloat, unitRead := utils.ConvertBytes(readRecent)
			writeFloat, unitWrite := utils.ConvertBytes(writeRecent)
			readRecent, writeRecent = uint64(readFloat), uint64(writeFloat)
			Part.CurRead = fmt.Sprintf("%d%s", readRecent, unitRead)
			Part.CurWrite = fmt.Sprintf("%d%s", writeRecent, unitWrite)
		} else {
			Part.CurRead = fmt.Sprintf("%d%s", 0, "B")
			Part.CurWrite = fmt.Sprintf("%d%s", 0, "B")
		}
		Part.TotalRead, Part.TotalWrite = curRead, curWrite
	}

	// converts self.Partitions into self.Rows which is a [][]String
	sortedPartitions := []string{}
	for seriesName := range self.Partitions {
		sortedPartitions = append(sortedPartitions, seriesName)
	}
	sort.Strings(sortedPartitions)

	self.Rows = make([][]string, len(self.Partitions))
	for i, key := range sortedPartitions {
		Part := self.Partitions[key]
		self.Rows[i] = make([]string, 6)
		self.Rows[i][0] = Part.Device
		self.Rows[i][1] = Part.Mount
		self.Rows[i][2] = fmt.Sprintf("%d%%", Part.UsedPercent)
		self.Rows[i][3] = Part.Free
		self.Rows[i][4] = Part.CurRead
		self.Rows[i][5] = Part.CurWrite
	}
}

// ColResize overrides the default ColResize in the termui table.
func (self *Disk) ColResize() {
	self.ColWidths = []int{
		4,
		utils.Max(5, self.X-33),
		4, 5, 5, 5,
	}

	self.CellXPos = []int{}
	cur := 1
	for _, w := range self.ColWidths {
		self.CellXPos = append(self.CellXPos, cur)
		cur += w
		cur += self.Gap
	}
}