Files
BanForge/internal/parser/parser.go
d3m0k1d 4e80b5148d
All checks were successful
CD - BanForge Release / release (push) Successful in 3m23s
docs: add new docs
2026-01-20 21:14:07 +03:00

125 lines
2.3 KiB
Go

package parser
import (
"bufio"
"os"
"os/exec"
"time"
"github.com/d3m0k1d/BanForge/internal/logger"
)
type Event struct {
Data string
}
type Scanner struct {
scanner *bufio.Scanner
ch chan Event
stopCh chan struct{}
logger *logger.Logger
cmd *exec.Cmd
file *os.File
pollDelay time.Duration
}
func NewScannerTail(path string) (*Scanner, error) {
cmd := exec.Command("tail", "-F", "-n", "10", path)
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
return &Scanner{
scanner: bufio.NewScanner(stdout),
ch: make(chan Event, 100),
stopCh: make(chan struct{}),
logger: logger.New(false),
file: nil,
cmd: cmd,
pollDelay: 100 * time.Millisecond,
}, nil
}
func NewScannerJournald(unit string) (*Scanner, error) {
cmd := exec.Command("journalctl", "-u", unit, "-f", "-n", "0", "-o", "short", "--no-pager")
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
return &Scanner{
scanner: bufio.NewScanner(stdout),
ch: make(chan Event, 100),
stopCh: make(chan struct{}),
logger: logger.New(false),
cmd: cmd,
file: nil,
pollDelay: 100 * time.Millisecond,
}, nil
}
func (s *Scanner) Start() {
s.logger.Info("Scanner started")
go func() {
for {
select {
case <-s.stopCh:
s.logger.Info("Scanner stopped")
return
default:
if s.scanner.Scan() {
s.ch <- Event{
Data: s.scanner.Text(),
}
s.logger.Info("Scanner event", "data", s.scanner.Text())
} else {
if err := s.scanner.Err(); err != nil {
s.logger.Error("Scanner error")
return
}
}
}
}
}()
}
func (s *Scanner) Stop() {
close(s.stopCh)
if s.cmd != nil && s.cmd.Process != nil {
s.logger.Info("Stopping process", "pid", s.cmd.Process.Pid)
err := s.cmd.Process.Kill()
if err != nil {
s.logger.Error("Failed to kill process", "err", err)
}
err = s.cmd.Wait()
if err != nil {
s.logger.Error("Failed to wait process", "err", err)
}
}
if s.file != nil {
if err := s.file.Close(); err != nil {
s.logger.Error("Failed to close file", "err", err)
}
}
time.Sleep(150 * time.Millisecond)
close(s.ch)
}
func (s *Scanner) Events() <-chan Event {
return s.ch
}