diff --git a/bootstrap/service/fsd.go b/bootstrap/service/fsd.go index d3fea9a..1bafd81 100644 --- a/bootstrap/service/fsd.go +++ b/bootstrap/service/fsd.go @@ -4,12 +4,15 @@ import ( "context" "errors" "github.com/renorris/openfsd/client" + "github.com/renorris/openfsd/postoffice" + "github.com/renorris/openfsd/protocol" "github.com/renorris/openfsd/servercontext" "log" "net" "os" "slices" "sync" + "time" ) type FSDService struct{} @@ -39,7 +42,6 @@ func (s *FSDService) Start(ctx context.Context, doneErr chan<- error) (err error func (s *FSDService) boot(ctx context.Context, listener *net.TCPListener) error { defer listener.Close() - defer log.Println("FSD server shutting down...") incomingConns := make(chan *net.TCPConn) @@ -48,6 +50,10 @@ func (s *FSDService) boot(ctx context.Context, listener *net.TCPListener) error // Track each client connection in a wait group waitGroup := sync.WaitGroup{} + // Start heartbeat worker + waitGroup.Add(1) + go s.heartbeatWorker(ctx, &waitGroup) + for { select { // Handle incoming connections @@ -114,3 +120,25 @@ func (s *FSDService) resolveAndListen() (listener *net.TCPListener, err error) { return listener, nil } + +func (s *FSDService) heartbeatWorker(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + + heartbeatPacket := "#DLSERVER:*:0:0" + protocol.PacketDelimiter + + ticker := time.NewTicker(30 * time.Second) + defer ticker.Stop() + + // Send server heartbeat every 30 seconds + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + servercontext.PostOffice().ForEachRegistered(func(name string, address postoffice.Address) bool { + address.SendMail(heartbeatPacket) + return true + }) + } + } +}