重构 auto-check:拆分包架构,精简 workflow 为纯调度循环

各包职责:
- config: 分类 YAML 配置
- model: Device/IP/MAC 公共类型
- discovery: 扫描 + ARP MAC 解析 + Devices 变量
- sshclient: SSH 连接
- stress: stress-ng/stressapptest 压测 + Results 变量
- report: 80mm 热敏模板/sparkline/打印 + Printed 变量
- workflow: 永久循环调度 + Start/Stop

workflow 已精简为 100 行纯编排,所有业务逻辑下沉各包
This commit is contained in:
张威33321
2026-08-11 20:58:19 +08:00
parent 19f6050147
commit 700ba91883
17 changed files with 867 additions and 516 deletions

View File

@@ -0,0 +1,257 @@
package report
import (
"bufio"
"fmt"
"io"
"net"
"os"
"os/exec"
"runtime"
"strings"
"time"
"auto-check/pkg/config"
)
// Printed 打印状态表IP → 上次打印的状态),包级公开
// 用于"状态变化才重新打印"策略
var Printed = make(map[string]string)
// ============================
// Printer 接口 — 打印后端抽象
// ============================
// Printer 报告打印机
type Printer interface {
Print(text string) error
Close() error
}
// ============================
// 打印配置
// ============================
// DefaultPrintConfig 默认打印配置80mm 热敏)
func DefaultPrintConfig() config.PrintConfig {
return config.PrintConfig{
Backend: "system",
Width: 42,
Charset: "utf-8",
}
}
// ============================
// ESC/POS 指令生成USB 与网络后端共用)
// ============================
// writeEscpos 将文本转为 ESC/POS 指令流写入 writer
func writeEscpos(w io.Writer, text string) error {
bw := bufio.NewWriter(w)
// 初始化打印机
bw.WriteString("\x1b@") // ESC @ 复位
bw.WriteString("\x1b3\x18") // 行距 24点
bw.WriteString("\x1bM\x00") // 标准字体
bw.WriteString("\x1ba\x00") // 左对齐
// 文本内容UTF-8 直发,打印机需支持)
for _, line := range strings.Split(text, "\n") {
bw.WriteString(line)
bw.WriteString("\n")
}
// 走纸 + 切纸
bw.WriteString("\n\n") // 尾部空行
bw.WriteString("\x1di") // 切纸(部分机型)
return bw.Flush()
}
// ============================
// 后端实现
// ============================
// SystemPrinter 系统打印后端lp/lpr/print
type SystemPrinter struct {
printerName string
command string
}
// NewSystemPrinter 创建系统打印机
// printerName 为空使用系统默认打印机
func NewSystemPrinter(printerName string) *SystemPrinter {
command := "lpr"
if runtime.GOOS == "windows" {
command = "print"
}
return &SystemPrinter{printerName: printerName, command: command}
}
// Print 发送文本到系统打印机
func (p *SystemPrinter) Print(text string) error {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
// 临时文件方式print 命令需要文件)
tmp, err := os.CreateTemp("", "auto-check-*.txt")
if err != nil {
return err
}
name := tmp.Name()
if _, err := tmp.WriteString(text); err != nil {
tmp.Close()
return err
}
tmp.Close()
defer os.Remove(name)
if p.printerName != "" {
cmd = exec.Command("cmd", "/c", "print", "/D:"+p.printerName, name)
} else {
cmd = exec.Command("cmd", "/c", "print", name)
}
default:
args := []string{}
if p.printerName != "" {
args = append(args, "-P", p.printerName)
}
cmd = exec.Command(p.command, append(args, "-")...)
cmd.Stdin = strings.NewReader(text)
}
return cmd.Run()
}
// Close 系统打印无需关闭
func (p *SystemPrinter) Close() error { return nil }
// ============================
// ESCPOSPrinter — 网络热敏直连9100
// ============================
// ESCPOSPrinter 网络 ESC/POS 打印机
type ESCPOSPrinter struct {
conn net.Conn
}
// NewESCPOSPrinter 连接网络 ESC/POS 打印机
// address 格式: 192.168.1.100:9100
func NewESCPOSPrinter(address string) (*ESCPOSPrinter, error) {
conn, err := net.DialTimeout("tcp", address, 5*time.Second)
if err != nil {
return nil, fmt.Errorf("连接打印机 %s 失败: %w", address, err)
}
return &ESCPOSPrinter{conn: conn}, nil
}
// Print 发送文本(自动转 ESC/POS 指令)
func (p *ESCPOSPrinter) Print(text string) error {
return writeEscpos(p.conn, text)
}
// Close 关闭连接
func (p *ESCPOSPrinter) Close() error {
if p.conn != nil {
return p.conn.Close()
}
return nil
}
// ============================
// USBPrinter — USB 热敏直连
// ============================
// USBPrinter USB ESC/POS 打印机
// Windows: \\.\usb001或打印机端口名
// Linux: /dev/usb/lp0或 lp1...
type USBPrinter struct {
dev *os.File
}
// defaultUSBDevice 默认 USB 设备路径
func defaultUSBDevice() string {
if runtime.GOOS == "windows" {
return `\\.\usb001`
}
return "/dev/usb/lp0"
}
// NewUSBPrinter 打开 USB 打印机设备
// device 为空时自动探测Linux /dev/usb/lp0Windows \\.\usb001
func NewUSBPrinter(device string) (*USBPrinter, error) {
if device == "" || device == "auto" {
device = defaultUSBDevice()
}
f, err := os.OpenFile(device, os.O_WRONLY, 0)
if err != nil {
return nil, fmt.Errorf("打开 USB 打印机 %s 失败: %w", device, err)
}
return &USBPrinter{dev: f}, nil
}
// Print 发送文本(自动转 ESC/POS 指令)
func (p *USBPrinter) Print(text string) error {
return writeEscpos(p.dev, text)
}
// Close 关闭设备
func (p *USBPrinter) Close() error {
if p.dev != nil {
return p.dev.Close()
}
return nil
}
// ============================
// FilePrinter — 文件后端(调试/重定向)
// ============================
// FilePrinter 文件打印后端
type FilePrinter struct {
path string
f *os.File
}
// NewFilePrinter 创建文件打印机
func NewFilePrinter(path string) (*FilePrinter, error) {
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
return &FilePrinter{path: path, f: f}, nil
}
// Print 追加写入文件
func (p *FilePrinter) Print(text string) error {
_, err := p.f.WriteString(text + "\n\n")
return err
}
// Close 关闭文件
func (p *FilePrinter) Close() error {
return p.f.Close()
}
// ============================
// 工厂
// ============================
// NewPrinter 按配置创建打印机
func NewPrinter(cfg config.PrintConfig) (Printer, error) {
if !cfg.Enabled {
return nil, nil
}
switch cfg.Backend {
case "system":
return NewSystemPrinter(cfg.Device), nil
case "escpos":
return NewESCPOSPrinter(cfg.Device)
case "usb":
return NewUSBPrinter(cfg.Device)
case "file":
return NewFilePrinter(cfg.Device)
default:
return nil, fmt.Errorf("未知打印后端: %s", cfg.Backend)
}
}