main.go 11 KB
Newer Older
liming6's avatar
liming6 committed
1
2
3
package tui

import (
4
	"get-container/cmd/hytop/backend"
liming6's avatar
liming6 committed
5
	"get-container/gpu"
liming6's avatar
liming6 committed
6
	"get-container/utils"
liming6's avatar
liming6 committed
7
8
	"time"

liming6's avatar
liming6 committed
9
10
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
liming6's avatar
liming6 committed
11
12
13
14
)

const (
	DCUTopVersion = "1.0.0"
liming6's avatar
liming6 committed
15
16
)

liming6's avatar
liming6 committed
17
18
19
20
21
22
23
24
25
var (
	HeightLightStyle    = lipgloss.NewStyle().Background(lipgloss.Color("#00fffb7a")) // 高亮风格
	SelectedStyle       = lipgloss.NewStyle().Foreground(lipgloss.Color("#ffb81fe3")) // 被选中的风格
	HeightSelectedStyle = lipgloss.NewStyle().Background(lipgloss.Color("#ffb81fe3")) // 既被选中,又高亮的风格

	LowLeightStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#442d2d"))
	NormalStyle    = lipgloss.NewStyle().Foreground(lipgloss.Color("#e6e6e6eb"))
)

liming6's avatar
liming6 committed
26
27
// ModelMsg 模型信息,在父组件和各个子组件间共享信息
type ModelMsg struct {
liming6's avatar
liming6 committed
28
29
	t          time.Time                        // 当前时间
	Version    *gpu.HYVersionInfo               // gpu版本相关信息
30
31
	DCUPidInfo map[int][]backend.DCUProcessInfo // 使用dcu的进程信息
	systemInfo *utils.SysInfo                   // 系统信息
liming6's avatar
liming6 committed
32
33
	MyVersion  string                           // 本软件的版本
	DCUInfo    *backend.DCUInfoMap              // dcu相关信息
liming6's avatar
liming6 committed
34
35
36
}

type TickMsg time.Time
37
38
39
40
41
42
43
44
type ProcessAction int

const (
	PAKill ProcessAction = 9
	PAInt  ProcessAction = 2
	PATerm ProcessAction = 15
	PANone ProcessAction = 0
)
liming6's avatar
liming6 committed
45

liming6's avatar
liming6 committed
46
47
// ActionMsg 动作消息
type ActionMsg struct {
48
49
50
51
52
53
54
	SelectPids     map[int32]bool // 选择的pid进程
	Action         *ProcessAction // 对选择的pid的动作
	PidView        *int32         // 进程视图指标的pid号,为null表示没有进入进程指标视图
	PointPid       *int32         // 指针指向的pid,为null表示没有选择进程
	PidEnvView     *int32         // 进程环境变量视图的pid号,为null表示不进入进程环境变量视图
	PidTreeView    *int32         // 进入pstree视图的pid号,为null表示不进入pstree视图
	TargetDCUIndex *int           // PointPid使用的dcu index
liming6's avatar
liming6 committed
55
56
}

liming6's avatar
liming6 committed
57
58
// ModelMain tui主模型类
type ModelMain struct {
liming6's avatar
liming6 committed
59
60
61
	width, height int // 终端尺寸
	Header        *ModelHeader
	DCUInfo       *ModelDCUInfo
liming6's avatar
liming6 committed
62
	SysLoad       *ModelSysLoad
63
	ProcessInfo   *ModelProcessInfo
liming6's avatar
liming6 committed
64
	modelMsg      *ModelMsg
liming6's avatar
liming6 committed
65
	actionMsg     *ActionMsg
liming6's avatar
liming6 committed
66
67
}

liming6's avatar
liming6 committed
68
func NewModelMain(width, height int) ModelMain {
liming6's avatar
liming6 committed
69
	result := ModelMain{}
liming6's avatar
liming6 committed
70
71
	result.width = width
	result.height = height
72
73
	result.Header = NewModelHeader()
	result.DCUInfo = NewModelDCUInfo(width, height)
liming6's avatar
liming6 committed
74
	result.SysLoad = NewModelSysLoad(width)
75
	result.ProcessInfo = NewModelProcessInfo(width)
liming6's avatar
liming6 committed
76
	result.actionMsg = &ActionMsg{}
liming6's avatar
liming6 committed
77
	return result
liming6's avatar
liming6 committed
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
}

func tickCmd() tea.Cmd {
	return tea.Every(time.Second, func(t time.Time) tea.Msg {
		return TickMsg(t)
	})
}

func sendMsgCmd(modelMsg *ModelMsg) tea.Cmd {
	return func() tea.Msg {
		return *modelMsg
	}
}

// Init 初始化信息
func (m *ModelMain) Init() tea.Cmd {
liming6's avatar
liming6 committed
94
95
	modelMsg := ModelMsg{}
	if err := initModelInfo(&modelMsg); err != nil {
liming6's avatar
liming6 committed
96
97
		return tea.Quit
	}
liming6's avatar
liming6 committed
98
99
100
101
	cmds := make([]tea.Cmd, 0)
	if c := m.Header.Init(); c != nil {
		cmds = append(cmds, c)
	}
liming6's avatar
liming6 committed
102
103
104
	if c := m.DCUInfo.Init(); c != nil {
		cmds = append(cmds, c)
	}
liming6's avatar
liming6 committed
105
106
107
	if c := m.SysLoad.Init(); c != nil {
		cmds = append(cmds, c)
	}
108
109
110
	if c := m.ProcessInfo.Init(); c != nil {
		cmds = append(cmds, c)
	}
liming6's avatar
liming6 committed
111
	m.modelMsg = &modelMsg
liming6's avatar
liming6 committed
112
	// 将调用初始化方法
liming6's avatar
liming6 committed
113
	cmds = append(cmds, tickCmd(), sendMsgCmd(&modelMsg))
liming6's avatar
liming6 committed
114
115
116
117
118
119
120
121
122
	return tea.Batch(cmds...)
}

func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := inputMsg.(type) {
	case tea.KeyMsg: // 键盘事件
		switch msg.String() {
		case "ctrl+c", "q":
			return m, tea.Quit
liming6's avatar
liming6 committed
123
124
125
126
127
128
129
130
131
132
133
		case "up":
			cmd := m.handleKeyUp()
			return m, cmd
		case "down":
			cmd := m.handleKeyDown()
			return m, cmd
		case "enter":
			return m, tea.Quit
		case "h":
			return m, tea.Quit
		case "k":
134
135
			cmd := m.handleKeyK()
			return m, cmd
liming6's avatar
liming6 committed
136
137
138
139
140
141
		case "esc":
			cmd := m.handleKeyEsc()
			return m, cmd
		case " ":
			cmd := m.handleKeySpace()
			return m, cmd
liming6's avatar
liming6 committed
142
143
		}
	case TickMsg: // 定时事件
liming6's avatar
liming6 committed
144
		updateModelInfo(m.modelMsg, time.Time(msg))
liming6's avatar
liming6 committed
145
146
147
		header, _ := m.Header.Update(m.modelMsg)
		dcuInfo, _ := m.DCUInfo.Update(m.modelMsg)
		sysLoad, _ := m.SysLoad.Update(m.modelMsg)
148
		pidinfo, _ := m.ProcessInfo.Update(m.modelMsg)
liming6's avatar
liming6 committed
149
		m.Header = header.(*ModelHeader)
liming6's avatar
liming6 committed
150
		m.DCUInfo = dcuInfo.(*ModelDCUInfo)
liming6's avatar
liming6 committed
151
		m.SysLoad = sysLoad.(*ModelSysLoad)
152
		m.ProcessInfo = pidinfo.(*ModelProcessInfo)
liming6's avatar
liming6 committed
153
		return m, tickCmd()
liming6's avatar
liming6 committed
154
155
156
	case ModelMsg: // 初始化
		header, _ := m.Header.Update(m.modelMsg)
		dcuInfo, _ := m.DCUInfo.Update(m.modelMsg)
liming6's avatar
liming6 committed
157
		sysLoad, _ := m.SysLoad.Update(m.modelMsg)
158
		pidinfo, _ := m.ProcessInfo.Update(m.modelMsg)
liming6's avatar
liming6 committed
159
160
		m.Header = header.(*ModelHeader)
		m.DCUInfo = dcuInfo.(*ModelDCUInfo)
liming6's avatar
liming6 committed
161
		m.SysLoad = sysLoad.(*ModelSysLoad)
162
		m.ProcessInfo = pidinfo.(*ModelProcessInfo)
liming6's avatar
liming6 committed
163
		return m, nil
164
	case tea.WindowSizeMsg: // 窗口尺寸变化
liming6's avatar
liming6 committed
165
		m.width, m.height = msg.Width, msg.Height
166
167
168
169
170
171
172
173
		header, _ := m.Header.Update(msg)
		dcuInfo, _ := m.DCUInfo.Update(msg)
		sysLoad, _ := m.SysLoad.Update(msg)
		pidinfo, _ := m.ProcessInfo.Update(msg)
		m.Header = header.(*ModelHeader)
		m.DCUInfo = dcuInfo.(*ModelDCUInfo)
		m.SysLoad = sysLoad.(*ModelSysLoad)
		m.ProcessInfo = pidinfo.(*ModelProcessInfo)
liming6's avatar
liming6 committed
174
		return m, nil
liming6's avatar
liming6 committed
175
176
177
178
	}
	return m, nil
}

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
func (m *ModelMain) handleKeyK() tea.Cmd {
	if m.actionMsg == nil {
		return nil
	}
	if m.actionMsg.PointPid == nil && m.actionMsg.SelectPids == nil {
		return nil
	}
	var pa ProcessAction = PANone
	if m.actionMsg.Action == nil {
		m.actionMsg.Action = &pa
	}
	header, _ := m.Header.Update(m.actionMsg)
	dcuInfo, _ := m.DCUInfo.Update(m.actionMsg)
	sysLoad, _ := m.SysLoad.Update(m.actionMsg)
	pidinfo, _ := m.ProcessInfo.Update(m.actionMsg)
	m.Header = header.(*ModelHeader)
	m.DCUInfo = dcuInfo.(*ModelDCUInfo)
	m.SysLoad = sysLoad.(*ModelSysLoad)
	m.ProcessInfo = pidinfo.(*ModelProcessInfo)
	return nil
}

liming6's avatar
liming6 committed
201
func (m *ModelMain) handleKeyEsc() tea.Cmd {
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
	if m.actionMsg == nil {
		return nil
	}
	if m.actionMsg.Action != nil {
		m.actionMsg.Action = nil
		header, _ := m.Header.Update(m.actionMsg)
		dcuInfo, _ := m.DCUInfo.Update(m.actionMsg)
		sysLoad, _ := m.SysLoad.Update(m.actionMsg)
		pidinfo, _ := m.ProcessInfo.Update(m.actionMsg)
		m.Header = header.(*ModelHeader)
		m.DCUInfo = dcuInfo.(*ModelDCUInfo)
		m.SysLoad = sysLoad.(*ModelSysLoad)
		m.ProcessInfo = pidinfo.(*ModelProcessInfo)
		return nil
	}
	if m.actionMsg.PointPid != nil || m.actionMsg.SelectPids != nil || m.actionMsg.TargetDCUIndex != nil {
		m.actionMsg.PointPid = nil
		m.actionMsg.SelectPids = nil
		m.actionMsg.TargetDCUIndex = nil
		header, _ := m.Header.Update(m.actionMsg)
		dcuInfo, _ := m.DCUInfo.Update(m.actionMsg)
		sysLoad, _ := m.SysLoad.Update(m.actionMsg)
		pidinfo, _ := m.ProcessInfo.Update(m.actionMsg)
		m.Header = header.(*ModelHeader)
		m.DCUInfo = dcuInfo.(*ModelDCUInfo)
		m.SysLoad = sysLoad.(*ModelSysLoad)
		m.ProcessInfo = pidinfo.(*ModelProcessInfo)
	}
liming6's avatar
liming6 committed
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
	return nil
}

func (m *ModelMain) handleKeySpace() tea.Cmd {
	if m.actionMsg == nil || m.actionMsg.PointPid == nil {
		return nil
	}
	if m.actionMsg.SelectPids == nil {
		m.actionMsg.SelectPids = make(map[int32]bool)
	}
	_, have := m.actionMsg.SelectPids[*m.actionMsg.PointPid]
	if have {
		delete(m.actionMsg.SelectPids, *m.actionMsg.PointPid)
	} else {
		m.actionMsg.SelectPids[*m.actionMsg.PointPid] = true
	}
	m1, cmd1 := m.ProcessInfo.Update(m.actionMsg)
	m.ProcessInfo = m1.(*ModelProcessInfo)
	return cmd1
}

liming6's avatar
liming6 committed
251
func (m *ModelMain) View() string {
252
	return m.Header.View() + m.DCUInfo.View() + m.SysLoad.View() + m.ProcessInfo.View() + "\n"
liming6's avatar
liming6 committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
}

var myBorder = lipgloss.Border{
	Top:          "═",
	TopLeft:      "╒",
	TopRight:     "╕",
	Bottom:       "═",
	BottomLeft:   "╘",
	BottomRight:  "╛",
	Left:         "│",
	Right:        "│",
	MiddleLeft:   "├",
	MiddleRight:  "┤",
	Middle:       "┼",
	MiddleTop:    "┬",
	MiddleBottom: "┴",
}

liming6's avatar
liming6 committed
271
272
func initModelInfo(model *ModelMsg) error {
	model.t = time.Now()
liming6's avatar
liming6 committed
273
274
	model.MyVersion = DCUTopVersion
	if ver, err := gpu.GetHYVersionInfo(); err != nil {
liming6's avatar
liming6 committed
275
		return err
liming6's avatar
liming6 committed
276
	} else {
liming6's avatar
liming6 committed
277
		model.Version = ver
liming6's avatar
liming6 committed
278
	}
279
280
281
282
283
284
285
286
287
288
289
290
291
292
	model.DCUInfo = backend.DCUSInfoMap
	model.DCUPidInfo = backend.DCUSInfoMap.GetDCUProcessInfo2()
	if sinfo, err := utils.GetSysInfo(); err != nil {
		return err
	} else {
		model.systemInfo = sinfo
	}
	if err := model.DCUInfo.UpdateQuickInfo(); err != nil {
		return err
	}
	if err := model.DCUInfo.UpdateSlowInfo(); err != nil {
		return err
	}
	return nil
liming6's avatar
liming6 committed
293
294
}

liming6's avatar
liming6 committed
295
// updateModelInfo 更新模型信息
296
func updateModelInfo(modelMsg *ModelMsg, t time.Time) error {
liming6's avatar
liming6 committed
297
	modelMsg.t = t
298
299
300
301
302
303
304
305
306
307
	if sinfo, err := utils.GetSysInfo(); err != nil {
		return err
	} else {
		modelMsg.systemInfo = sinfo
	}
	modelMsg.DCUPidInfo = modelMsg.DCUInfo.GetDCUProcessInfo2()
	if err := modelMsg.DCUInfo.UpdateQuickInfo(); err != nil {
		return err
	}
	return nil
liming6's avatar
liming6 committed
308
}
liming6's avatar
liming6 committed
309
310
311
312
313
314
315
316

func (m *ModelMain) handleKeyUp() tea.Cmd {
	if m.actionMsg == nil {
		m.actionMsg = &ActionMsg{}
	}
	if m.modelMsg.DCUPidInfo == nil {
		return nil
	}
317
318
319
	if m.actionMsg.Action != nil {
		return nil
	}
liming6's avatar
liming6 committed
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
	processes := make([]backend.DCUProcessInfo, 0)
	for index := range 64 {
		p, have := m.modelMsg.DCUPidInfo[index]
		if have && len(p) > 0 {
			processes = append(processes, p...)
		}
	}
	processNum := len(processes)
	if processNum == 0 {
		return nil
	}
	index := 0
	if m.actionMsg.PointPid == nil {
		// 获取列表中的最后一个进程的pid
		index = processNum - 1
	} else {
		var targetIndex = -1
		for l := processNum - 1; l >= 0; l-- {
			if processes[l].Info.Pid == *m.actionMsg.PointPid {
				targetIndex = l - 1
				break
			}
		}
		if targetIndex == -1 {
			index = processNum - 1
		} else {
			index = targetIndex
		}
	}
	pid := processes[index].Info.Pid
	m.actionMsg.PointPid = &pid
	idx := processes[index].DCU
	m.actionMsg.TargetDCUIndex = &idx
353

liming6's avatar
liming6 committed
354
355
	m1, cmd1 := m.ProcessInfo.Update(m.actionMsg)
	m2, cmd2 := m.DCUInfo.Update(m.actionMsg)
356
	m3, cmd3 := m.SysLoad.Update(m.actionMsg)
liming6's avatar
liming6 committed
357
358
	m.ProcessInfo = m1.(*ModelProcessInfo)
	m.DCUInfo = m2.(*ModelDCUInfo)
359
360
	m.SysLoad = m3.(*ModelSysLoad)
	return tea.Batch(cmd1, cmd2, cmd3)
liming6's avatar
liming6 committed
361
362
363
364
365
366
367
368
369
}

func (m *ModelMain) handleKeyDown() tea.Cmd {
	if m.actionMsg == nil {
		m.actionMsg = &ActionMsg{}
	}
	if m.modelMsg.DCUPidInfo == nil {
		return nil
	}
370
371
372
	if m.actionMsg.Action != nil {
		return nil
	}
liming6's avatar
liming6 committed
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
	processes := make([]backend.DCUProcessInfo, 0)
	for index := range 64 {
		p, have := m.modelMsg.DCUPidInfo[index]
		if have && len(p) > 0 {
			processes = append(processes, p...)
		}
	}
	processNum := len(processes)
	if processNum == 0 {
		return nil
	}
	index := 0
	if m.actionMsg.PointPid == nil {
		index = 0
	} else {
		var targetIndex = -1
		for l := 0; l < processNum-1; l++ {
			if processes[l].Info.Pid == *m.actionMsg.PointPid {
				targetIndex = l + 1
				if targetIndex >= processNum {
					targetIndex = 0
				}
				break
			}
		}
		if targetIndex == -1 {
			index = 0
		} else {
			index = targetIndex

		}
	}
	pid := processes[index].Info.Pid
	m.actionMsg.PointPid = &pid
	idx := processes[index].DCU
	m.actionMsg.TargetDCUIndex = &idx
	m1, cmd1 := m.ProcessInfo.Update(m.actionMsg)
	m2, cmd2 := m.DCUInfo.Update(m.actionMsg)
411
	m3, cmd3 := m.SysLoad.Update(m.actionMsg)
liming6's avatar
liming6 committed
412
413
	m.ProcessInfo = m1.(*ModelProcessInfo)
	m.DCUInfo = m2.(*ModelDCUInfo)
414
415
	m.SysLoad = m3.(*ModelSysLoad)
	return tea.Batch(cmd1, cmd2, cmd3)
liming6's avatar
liming6 committed
416
}