hdmistat/internal/hdmistat/daemon.go
sneak 402c0797d5 Initial implementation of hdmistat - Linux framebuffer system stats display
Features:
- Beautiful system statistics display using IBM Plex Mono font
- Direct framebuffer rendering without X11/Wayland
- Multiple screens with automatic carousel rotation
- Real-time system monitoring (CPU, memory, disk, network, processes)
- Systemd service integration with install command
- Clean architecture using uber/fx dependency injection

Architecture:
- Cobra CLI with daemon, install, status, and info commands
- Modular design with separate packages for display, rendering, and stats
- Font embedding for zero runtime dependencies
- Layout API for clean text rendering
- Support for multiple screen types (overview, top CPU, top memory)

Technical details:
- Uses gopsutil for cross-platform system stats collection
- Direct Linux framebuffer access via memory mapping
- Anti-aliased text rendering with freetype
- Configurable screen rotation and update intervals
- Structured logging with slog
- Comprehensive test coverage and linting setup

This initial version provides a solid foundation for displaying rich
system information on resource-constrained devices like Raspberry Pis.
2025-07-23 12:55:42 +02:00

87 lines
1.9 KiB
Go

package hdmistat
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
"git.eeqj.de/sneak/hdmistat/internal/app"
"git.eeqj.de/sneak/hdmistat/internal/display"
"git.eeqj.de/sneak/hdmistat/internal/font"
"git.eeqj.de/sneak/hdmistat/internal/renderer"
"git.eeqj.de/sneak/hdmistat/internal/statcollector"
"github.com/golang/freetype/truetype"
"github.com/spf13/cobra"
"go.uber.org/fx"
)
var (
framebufferDevice string
configFile string
daemonCmd = &cobra.Command{
Use: "daemon",
Short: "Run hdmistat as a daemon",
Long: `Run hdmistat as a daemon that displays system statistics on the framebuffer.`,
Run: runDaemon,
}
)
func init() {
daemonCmd.Flags().StringVarP(&framebufferDevice, "framebuffer", "f", "/dev/fb0", "Framebuffer device to use")
daemonCmd.Flags().StringVarP(&configFile, "config", "c", "/etc/hdmistat/config.yaml", "Configuration file path")
}
func runDaemon(cmd *cobra.Command, args []string) {
// Set up signal handling
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigChan
logger.Info("received shutdown signal")
cancel()
}()
// Create fx application
fxApp := fx.New(
fx.Provide(
func() *slog.Logger { return logger },
func() context.Context { return ctx },
// Provide font
func() (*truetype.Font, error) {
return font.LoadIBMPlexMono()
},
// Provide display
func(logger *slog.Logger) (display.Display, error) {
return display.NewFramebufferDisplay(framebufferDevice, logger)
},
// Provide collector
func(logger *slog.Logger) statcollector.Collector {
return statcollector.NewSystemCollector(logger)
},
// Provide renderer
renderer.NewRenderer,
// Provide app
app.NewApp,
),
fx.Invoke(func(a *app.App) {
// App will be started by fx lifecycle
}),
)
// Start the application
fxApp.Run()
}