feat: 添加单源爬取功能并优化数据库同步
新增单源爬取功能,支持在界面上单独更新每个数据源 添加数据库同步脚本,支持主从数据库结构同步和数据同步 优化华能集团爬虫的页面导航和稳定性 新增系统托盘功能,支持最小化到托盘
This commit is contained in:
194
widget/looker/sys_run/systray_run.go
Normal file
194
widget/looker/sys_run/systray_run.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/getlantern/systray"
|
||||
)
|
||||
|
||||
var (
|
||||
sendPipe *os.File
|
||||
receivePipe *os.File
|
||||
logFile *os.File
|
||||
)
|
||||
|
||||
func initLog() {
|
||||
var err error
|
||||
logFile, err = os.OpenFile("systray_debug.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
// failsafe
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func logMsg(format string, args ...interface{}) {
|
||||
if logFile != nil {
|
||||
fmt.Fprintf(logFile, format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
initLog()
|
||||
logMsg("Systray process started")
|
||||
|
||||
// 使用 Stdin 和 Stdout 与主进程通信
|
||||
// 主进程将 cmd.Stdin 连接到 pipes,将 cmd.Stdout 连接到 pipes
|
||||
// 所以这里我们直接使用 os.Stdin 读取,os.Stdout 发送
|
||||
|
||||
sendPipe = os.Stdout
|
||||
receivePipe = os.Stdin
|
||||
|
||||
// 启动系统托盘
|
||||
logMsg("Calling systray.Run")
|
||||
systray.Run(onReady, onExit)
|
||||
}
|
||||
|
||||
func onReady() {
|
||||
logMsg("systray onReady called")
|
||||
// 设置托盘图标 - 使用简单的图标
|
||||
systray.SetIcon(getIcon())
|
||||
systray.SetTitle("Bidding Looker")
|
||||
systray.SetTooltip("Bidding Looker - 招标信息查看器")
|
||||
|
||||
// 显示窗口菜单项
|
||||
mShow := systray.AddMenuItem("显示窗口", "显示主窗口")
|
||||
mQuit := systray.AddMenuItem("退出", "退出程序")
|
||||
|
||||
// 监听来自主进程的消息
|
||||
go monitorPipe()
|
||||
|
||||
// 处理菜单点击
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-mShow.ClickedCh:
|
||||
logMsg("Show menu clicked")
|
||||
// 发送显示窗口消息到主进程
|
||||
sendMessage("SHOW")
|
||||
case <-mQuit.ClickedCh:
|
||||
logMsg("Quit menu clicked")
|
||||
// 发送退出消息到主进程
|
||||
sendMessage("QUIT")
|
||||
systray.Quit()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 监听系统信号
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-sigCh
|
||||
logMsg("Received signal, quitting")
|
||||
systray.Quit()
|
||||
}()
|
||||
}
|
||||
|
||||
func onExit() {
|
||||
logMsg("systray onExit called")
|
||||
// 清理资源
|
||||
}
|
||||
|
||||
func monitorPipe() {
|
||||
logMsg("Starting monitorPipe")
|
||||
reader := bufio.NewReader(receivePipe)
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
logMsg("Pipe EOF, quitting")
|
||||
// 主进程关闭了管道(可能退出了),我们也退出
|
||||
systray.Quit()
|
||||
return
|
||||
}
|
||||
logMsg("Pipe read error: %v", err)
|
||||
fmt.Fprintf(os.Stderr, "Pipe read error: %v\n", err)
|
||||
return
|
||||
}
|
||||
// 处理来自主进程的消息 (日志输出到 Stderr,避免污染 Stdout)
|
||||
logMsg("Received from main: %s", line)
|
||||
fmt.Fprintf(os.Stderr, "Received from main: %s", line)
|
||||
}
|
||||
}
|
||||
|
||||
func sendMessage(message string) {
|
||||
logMsg("Sending message: %s", message)
|
||||
_, err := sendPipe.WriteString(message + "\n")
|
||||
if err != nil {
|
||||
logMsg("Failed to send message: %v", err)
|
||||
fmt.Fprintf(os.Stderr, "Failed to send message: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 简单的图标数据(16x16 像素的简单图标)
|
||||
// 使用 PNG 格式,这是 systray 库在 Windows 上的推荐格式
|
||||
func getIcon() []byte {
|
||||
// PNG 文件签名
|
||||
// IHDR chunk (图像头): 16x16, 8-bit RGBA
|
||||
// IDAT chunk (图像数据): 简单的蓝色方块图标
|
||||
// IEND chunk (文件结束)
|
||||
return []byte{
|
||||
// PNG 签名 (8 bytes)
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
|
||||
|
||||
// IHDR chunk
|
||||
0x00, 0x00, 0x00, 0x0D, // Length: 13 bytes
|
||||
0x49, 0x48, 0x44, 0x52, // Type: IHDR
|
||||
0x00, 0x00, 0x00, 0x10, // Width: 16
|
||||
0x00, 0x00, 0x00, 0x10, // Height: 16
|
||||
0x08, // Bit depth: 8
|
||||
0x06, // Color type: RGBA
|
||||
0x00, 0x00, 0x00, // Compression, Filter, Interlace
|
||||
0x5D, 0x8A, 0x7F, 0xD4, // CRC
|
||||
|
||||
// IDAT chunk (使用最简单的 PNG 编码)
|
||||
0x00, 0x00, 0x01, 0x6D, // Length: 365 bytes
|
||||
0x49, 0x44, 0x41, 0x54, // Type: IDAT
|
||||
// 压缩数据 (zlib 格式)
|
||||
0x78, 0x9C, // zlib header (default compression)
|
||||
// Deflate 压缩块
|
||||
0x63, 0x18, 0x19, 0x60, 0x28, 0x55, 0xF6, 0x7F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x05, 0x00, 0x01, 0x0A, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x52, 0x4B, 0x8C, 0x36, // CRC
|
||||
|
||||
// IEND chunk
|
||||
0x00, 0x00, 0x00, 0x00, // Length: 0 bytes
|
||||
0x49, 0x45, 0x4E, 0x44, // Type: IEND
|
||||
0xAE, 0x42, 0x60, 0x82, // CRC
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user