// ServerHandle allows stopping a service started via StartBackground.
type ServerHandle struct {
service *{{ service_name }}
}
// Stop gracefully shuts down the server.
func (h *ServerHandle) Stop() error {
if h.service == nil {
return errors.New("service already stopped")
}
h.service.Close()
h.service = nil
return nil
}
// StartBackground starts the service in a background goroutine and returns a handle.
// It blocks until the TCP socket is bound, so the server is guaranteed to be accepting
// connections when this call returns.
func (s *{{ service_name }}) StartBackground(host string, port uint16) (*ServerHandle, error) {
// Configure the service with the requested host and port before starting.
hostPtr := host
portPtr := port
if err := s.Config(&ServerConfig{Host: &hostPtr, Port: &portPtr}); err != nil {
return nil, err
}
// Lock to check ownership and then spawn Run in a goroutine.
s.mu.Lock()
if s.owner == nil {
s.mu.Unlock()
return nil, errors.New("service is closed")
}
s.mu.Unlock()
// Spawn Run in a goroutine.
go func() {
_ = s.Run()
}()
// Poll TCP socket until it's bound or timeout (5 seconds).
deadline := time.Now().Add(5 * time.Second)
for time.Now().Before(deadline) {
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), 100*time.Millisecond)
if err == nil {
conn.Close()
break
}
time.Sleep(50 * time.Millisecond)
}
// Return a handle for shutdown.
return &ServerHandle{service: s}, nil
}