dcuinfo.go 9.61 KB
Newer Older
liming6's avatar
liming6 committed
1
2
3
package tui

import (
liming6's avatar
liming6 committed
4
	"fmt"
5
	"get-container/utils"
6
	"regexp"
liming6's avatar
liming6 committed
7
8
	"strconv"
	"strings"
liming6's avatar
liming6 committed
9

liming6's avatar
liming6 committed
10
	"github.com/charmbracelet/bubbles/progress"
liming6's avatar
liming6 committed
11
	tea "github.com/charmbracelet/bubbletea"
liming6's avatar
liming6 committed
12
	"github.com/charmbracelet/lipgloss"
liming6's avatar
liming6 committed
13
14
	"github.com/lucasb-eyer/go-colorful"
	"github.com/muesli/gamut"
15
	"github.com/muesli/termenv"
liming6's avatar
liming6 committed
16
17
18
)

type ModelDCUInfo struct {
19
20
21
22
23
24
25
26
27
28
	width, height          int            // 屏幕尺寸
	pro                    progress.Model // 进度条
	proLowLeight           progress.Model // 低亮度进度条
	proWidth               int            // 进度条宽度
	modMsg                 *ModelMsg      // 缓存的模型信息
	actionMsg              *ActionMsg     // 缓存的动作信息
	darkModule             bool           // 是否为黑暗模式
	top, middle, bottom    string         // 缓存的边框
	topL, middleL, bottomL string         // 缓存的低亮度边框
	subLin                 int            // 边框更新标志
liming6's avatar
liming6 committed
29
30
}

liming6's avatar
liming6 committed
31
32
33
34
35
36
const (
	TopLine    = `╞═══════════════════════════════╪══════════════════════╪══════════════════════╪`
	MiddleLine = `├───────────────────────────────┼──────────────────────┼──────────────────────┼`
	BottomLine = `╞═══════════════════════════════╧══════════════════════╧══════════════════════╪`

	OtherWidth       = 8
liming6's avatar
liming6 committed
37
38
	StaticWidth      = 79 // 固定表格的宽度
	ProgressMinWidth = 15 // 进度条最小宽度
liming6's avatar
liming6 committed
39
40
)

41
42
43
44
var (
	ReDCUName = regexp.MustCompile(`(?i)^[A-Z0-9-_]*`)
)

45
func NewModelDCUInfo(w, h int) *ModelDCUInfo {
46
	return &ModelDCUInfo{width: w, height: h, darkModule: false}
liming6's avatar
liming6 committed
47
48
}

liming6's avatar
liming6 committed
49
func (m *ModelDCUInfo) Init() tea.Cmd {
50
	if m.width < StaticWidth+ProgressMinWidth+OtherWidth {
liming6's avatar
liming6 committed
51
52
53
		return tea.Quit
	}
	m.proWidth = ProgressMinWidth
54
55
	if m.width > StaticWidth+ProgressMinWidth+OtherWidth {
		m.proWidth = m.width - OtherWidth - StaticWidth
liming6's avatar
liming6 committed
56
	}
liming6's avatar
liming6 committed
57
58
59
60
	m.pro = progress.New(progress.WithColorProfile(termenv.TrueColor), progress.WithGradient("#0000ffff", "#ff0000ff"), progress.WithWidth(m.proWidth-5), progress.WithoutPercentage())
	c1, _ := colorful.MakeColor(gamut.Darker(lipgloss.Color("#0000ffff"), 0.8))
	c2, _ := colorful.MakeColor(gamut.Darker(lipgloss.Color("#ff0000ff"), 0.8))
	m.proLowLeight = progress.New(progress.WithColorProfile(termenv.TrueColor), progress.WithGradient(c1.Hex(), c2.Hex()), progress.WithWidth(m.proWidth-5), progress.WithoutPercentage())
liming6's avatar
liming6 committed
61
62
63
	return nil
}

liming6's avatar
liming6 committed
64
65
66
func (m *ModelDCUInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := inputMsg.(type) {
	case *ModelMsg:
67
68
69
70
71
		m.modMsg = msg
		return m, nil
	case tea.WindowSizeMsg:
		m.height = msg.Height
		m.width = msg.Width
liming6's avatar
liming6 committed
72
		return m, nil
liming6's avatar
liming6 committed
73
74
	case *ActionMsg:
		m.actionMsg = msg
liming6's avatar
liming6 committed
75
		if msg.Action != nil && msg.VM == VMMain {
76
77
78
79
			m.darkModule = true
		} else {
			m.darkModule = false
		}
liming6's avatar
liming6 committed
80
		return m, nil
liming6's avatar
liming6 committed
81
	}
liming6's avatar
liming6 committed
82
83
84
85
	return m, nil
}

func (m *ModelDCUInfo) View() string {
86
87
88
	if m.modMsg == nil {
		return ""
	}
liming6's avatar
liming6 committed
89
	lineWidth := 0
90
91
	qmap, qlock := m.modMsg.DCUInfo.GetQuitInfo()
	smap, slock := m.modMsg.DCUInfo.GetSlowInfo()
liming6's avatar
liming6 committed
92
	strBuilder := strings.Builder{}
liming6's avatar
liming6 committed
93
94
	strCache := strings.Builder{}
	var targetDCU int = -1
95
96
	if m.actionMsg != nil {
		targetDCU = m.actionMsg.TargetDCUIndex
liming6's avatar
liming6 committed
97
	}
98
99
100
101
	var borderStr string = myBorder.Left
	if m.darkModule {
		borderStr = LowLeightStyle.Render(borderStr)
	}
102
	infos := make([]string, 0)
liming6's avatar
liming6 committed
103
104

	for i := range 32 {
105
106
107
108
109
		qinfo, haveq := qmap[i]
		sinfo, haves := smap[i]
		if !(haveq || haves) {
			continue
		}
110
111
		isLowStyle := (targetDCU != qinfo.Id && targetDCU != -1) || m.darkModule
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
112
113
114
115

		strCache.WriteByte(' ')
		strCache.WriteString(FormatStr(strconv.Itoa(qinfo.Id), 4, lipgloss.Left))
		strCache.WriteByte(' ')
116
		strCache.WriteString(FormatStr(ReDCUName.FindString(qinfo.Name.OrElse("Unknow")), 8, lipgloss.Left))
liming6's avatar
liming6 committed
117
		strCache.WriteByte(' ')
118
		strCache.WriteString(FormatStr(qinfo.PerformanceLevel.OrElse("Unknow"), 15, lipgloss.Right))
liming6's avatar
liming6 committed
119
120
121
122
123
124
125
126
127
		strCache.WriteByte(' ')

		if isLowStyle {
			str := strCache.String()
			strBuilder.WriteString(LowLeightStyle.Render(str))
		} else {
			strBuilder.WriteString(strCache.String())
		}
		strCache.Reset()
128
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
129
130

		strCache.WriteByte(' ')
131
		strCache.WriteString(FormatStr(qinfo.BusId.OrElse("Unknow"), 13, lipgloss.Left))
liming6's avatar
liming6 committed
132
133
134
135
136
137
		strCache.WriteByte(' ')
		strCache.WriteString(FormatStr("Off", 6, lipgloss.Right))
		strCache.WriteByte(' ')
		if isLowStyle {
			str := strCache.String()
			strBuilder.WriteString(LowLeightStyle.Render(str))
liming6's avatar
liming6 committed
138
		} else {
liming6's avatar
liming6 committed
139
			strBuilder.WriteString(strCache.String())
liming6's avatar
liming6 committed
140
		}
liming6's avatar
liming6 committed
141
142
143
144
		strCache.Reset()

		strCache.WriteByte(' ')
		strCache.WriteString(FormatStr("Off", 16, lipgloss.Left))
145
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
146
		strCache.WriteByte(' ')
147
		if sinfo.Ecc.Load() {
liming6's avatar
liming6 committed
148
149
150
151
152
153
154
155
			strCache.WriteString(FormatStr("On", 3, lipgloss.Right))
		} else {
			strCache.WriteString(FormatStr("Off", 3, lipgloss.Right))
		}
		strCache.WriteByte(' ')
		if isLowStyle {
			str := strCache.String()
			strBuilder.WriteString(LowLeightStyle.Render(str))
liming6's avatar
liming6 committed
156
		} else {
liming6's avatar
liming6 committed
157
			strBuilder.WriteString(strCache.String())
liming6's avatar
liming6 committed
158
		}
liming6's avatar
liming6 committed
159
		strCache.Reset()
160
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
161
162
163

		if isLowStyle {
			strBuilder.WriteString(LowLeightStyle.Render(" DCU: "))
164
165
			strBuilder.WriteString(m.proLowLeight.ViewAs(float64(qinfo.DCUUTil.OrElse(0.0) / 100)))
			strBuilder.WriteString(LowLeightStyle.Render(fmt.Sprintf(" %3d%% ", int(qinfo.DCUUTil.OrElse(0.0)))))
liming6's avatar
liming6 committed
166
167
		} else {
			strBuilder.WriteString(" DCU: ")
168
169
			strBuilder.WriteString(m.pro.ViewAs(float64(qinfo.DCUUTil.OrElse(0.0) / 100)))
			strBuilder.WriteString(fmt.Sprintf(" %3d%% ", int(qinfo.DCUUTil.OrElse(0.0))))
liming6's avatar
liming6 committed
170
		}
171
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
172
		strBuilder.WriteByte('\n')
173
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
174
175

		strCache.WriteByte(' ')
176
		strCache.WriteString(FormatStr(qinfo.Fan.OrElse("N/A"), 4, lipgloss.Left))
liming6's avatar
liming6 committed
177
		strCache.WriteByte(' ')
178
179
180
181
182
183
184
185
186
187
		if qinfo.Temp.IsSome() {
			temp := qinfo.Temp.MustGet()
			if temp == 0 {
				strCache.WriteString(FormatStr("N/A", 6, lipgloss.Left))
			} else {
				strCache.WriteString(FormatStr(fmt.Sprintf("%.1f°C", temp), 6, lipgloss.Left))
			}
		} else {
			strCache.WriteString(FormatStr("N/A", 6, lipgloss.Left))
		}
liming6's avatar
liming6 committed
188
		strCache.WriteByte(' ')
189
		strCache.WriteString(FormatStr(fmt.Sprintf("%.1fW / %.1fW", qinfo.PwrAvg.OrElse(0.0), qinfo.PwrCap.OrElse(0.0)), 17, lipgloss.Right))
liming6's avatar
liming6 committed
190
191
192
193
194
195
196
197
198
		strCache.WriteByte(' ')

		if isLowStyle {
			str := strCache.String()
			strBuilder.WriteString(LowLeightStyle.Render(str))
		} else {
			strBuilder.WriteString(strCache.String())
		}
		strCache.Reset()
199
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
200
201
202

		if isLowStyle {
			strCache.WriteByte(' ')
203
			strCache.WriteString(FormatStr(fmt.Sprintf("%dMiB / %dMiB", qinfo.MemUsed.OrElse(0)/uint64(utils.MiB), qinfo.MemTotal.OrElse(0)/uint64(utils.MiB)), 20, lipgloss.Right))
liming6's avatar
liming6 committed
204
205
206
207
208
			strCache.WriteByte(' ')
			strBuilder.WriteString(LowLeightStyle.Render(strCache.String()))
			strCache.Reset()
		} else {
			strBuilder.WriteByte(' ')
209
			strBuilder.WriteString(FormatStr(fmt.Sprintf("%dMiB / %dMiB", qinfo.MemUsed.OrElse(0)/uint64(utils.MiB), qinfo.MemTotal.OrElse(0)/uint64(utils.MiB)), 20, lipgloss.Right))
liming6's avatar
liming6 committed
210
211
212
			strBuilder.WriteByte(' ')
		}

213
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
214
215
216

		if isLowStyle {
			strCache.WriteByte(' ')
217
			strCache.WriteString(FormatStr(fmt.Sprintf("%.1f%%", qinfo.DCUUTil.OrElse(0)), 6, lipgloss.Left))
liming6's avatar
liming6 committed
218
219
220
221
222
223
224
			strCache.WriteByte(' ')
			strCache.WriteString(FormatStr(sinfo.PwrMode.Load().(string), 13, lipgloss.Right))
			strCache.WriteByte(' ')
			strBuilder.WriteString(LowLeightStyle.Render(strCache.String()))
			strCache.Reset()
		} else {
			strBuilder.WriteByte(' ')
225
			strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1f%%", qinfo.DCUUTil.OrElse(0)), 6, lipgloss.Left))
liming6's avatar
liming6 committed
226
227
228
229
230
			strBuilder.WriteByte(' ')
			strBuilder.WriteString(FormatStr(sinfo.PwrMode.Load().(string), 13, lipgloss.Right))
			strBuilder.WriteByte(' ')
		}

231
		strBuilder.WriteString(borderStr)
liming6's avatar
liming6 committed
232
233
234

		if isLowStyle {
			strCache.WriteString(" Mem: ")
235
236
			strCache.WriteString(m.proLowLeight.ViewAs(float64(qinfo.MemUsed.OrElse(0)) / float64(qinfo.MemTotal.OrElse(1))))
			strCache.WriteString(LowLeightStyle.Render(fmt.Sprintf(" %3d%% ", int(100*float64(qinfo.MemUsed.OrElse(0))/float64(qinfo.MemTotal.OrElse(1))))))
liming6's avatar
liming6 committed
237
238
239
240
			strBuilder.WriteString(LowLeightStyle.Render(strCache.String()))
			strCache.Reset()
		} else {
			strBuilder.WriteString(" Mem: ")
241
			strBuilder.WriteString(m.pro.ViewAs(float64(qinfo.MemUsed.OrElse(0)) / float64(qinfo.MemTotal.OrElse(1))))
liming6's avatar
liming6 committed
242
			strBuilder.WriteByte(' ')
243
			strBuilder.WriteString(fmt.Sprintf("%3d%%", int(100*float64(qinfo.MemUsed.OrElse(0))/float64(qinfo.MemTotal.OrElse(1)))))
liming6's avatar
liming6 committed
244
245
			strBuilder.WriteByte(' ')
		}
246
247
		strBuilder.WriteString(borderStr)
		strBuilder.WriteByte('\n')
248
		infos = append(infos, strBuilder.String())
liming6's avatar
liming6 committed
249
250
		strBuilder.Reset()
	}
251
252
	slock.Unlock()
	qlock.Unlock()
liming6's avatar
liming6 committed
253
254
255
	if len(infos) > 0 {
		lineWidth = lipgloss.Width(infos[0])
	}
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
	subLen := max(lineWidth-StaticWidth-1, 0)
	if subLen != m.subLin {
		top := TopLine + strings.Repeat("═", subLen) + "╕"
		middle := MiddleLine + strings.Repeat("─", subLen) + "┤"
		bottom := BottomLine + strings.Repeat("═", subLen) + "╡"
		m.topL = LowLeightStyle.Render(top) + "\n"
		m.middleL = LowLeightStyle.Render(middle) + "\n"
		m.bottomL = LowLeightStyle.Render(bottom) + "\n"
		m.top = top + "\n"
		m.middle = middle + "\n"
		m.bottom = bottom + "\n"
	}
	if m.darkModule {
		return m.topL + strings.Join(infos, m.middleL) + m.bottomL
	} else {
		return m.top + strings.Join(infos, m.middle) + m.bottom
liming6's avatar
liming6 committed
272
	}
liming6's avatar
liming6 committed
273
}