add Stop function to module

This commit is contained in:
Joel Wetzell
2026-02-07 09:53:38 -06:00
parent 8f5091cf9b
commit 33ecc94097
19 changed files with 156 additions and 18 deletions

View File

@@ -17,6 +17,7 @@ type HTTPClient struct {
client *http.Client
router route.RouteIO
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -44,7 +45,9 @@ func (hc *HTTPClient) Run(ctx context.Context) error {
return errors.New("http.client unable to get router from context")
}
hc.router = router
hc.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
hc.ctx = moduleContext
hc.cancel = cancel
hc.client = &http.Client{
Timeout: 10 * time.Second,
@@ -79,3 +82,7 @@ func (hc *HTTPClient) Output(ctx context.Context, payload any) error {
return nil
}
func (hc *HTTPClient) Stop() {
hc.cancel()
}

View File

@@ -19,6 +19,7 @@ type HTTPServer struct {
ctx context.Context
router route.RouteIO
logger *slog.Logger
cancel context.CancelFunc
}
type ResponseIOError struct {
@@ -153,7 +154,9 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
return errors.New("http.server unable to get router from context")
}
hs.router = router
hs.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
hs.ctx = moduleContext
hs.cancel = cancel
httpServer := &http.Server{
Addr: fmt.Sprintf(":%d", hs.Port),
@@ -199,3 +202,7 @@ func (hs *HTTPServer) Output(ctx context.Context, payload any) error {
responseWriter.Write(payloadResponse.Body)
return nil
}
func (hs *HTTPServer) Stop() {
hs.cancel()
}

View File

@@ -21,6 +21,7 @@ type MIDIInput struct {
Port string
SendFunc func(midi.Message) error
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -61,7 +62,9 @@ func (mi *MIDIInput) Run(ctx context.Context) error {
return errors.New("midi.input unable to get router from context")
}
mi.router = router
mi.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
mi.ctx = moduleContext
mi.cancel = cancel
in, err := midi.FindInPort(mi.Port)
if err != nil {
@@ -88,3 +91,7 @@ func (mi *MIDIInput) Run(ctx context.Context) error {
func (mi *MIDIInput) Output(ctx context.Context, payload any) error {
return errors.New("midi.input output is not implemented")
}
func (mi *MIDIInput) Stop() {
mi.cancel()
}

View File

@@ -21,6 +21,7 @@ type MIDIOutput struct {
Port string
SendFunc func(midi.Message) error
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -62,7 +63,9 @@ func (mo *MIDIOutput) Run(ctx context.Context) error {
return errors.New("midi.output unable to get router from context")
}
mo.router = router
mo.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
mo.ctx = moduleContext
mo.cancel = cancel
out, err := midi.FindOutPort(mo.Port)
@@ -95,3 +98,7 @@ func (mo *MIDIOutput) Output(ctx context.Context, payload any) error {
return mo.SendFunc(payloadMessage)
}
func (mo *MIDIOutput) Stop() {
mo.cancel()
}

View File

@@ -19,6 +19,7 @@ type Module interface {
Id() string
Type() string
Run(context.Context) error
Stop()
Output(context.Context, any) error
}

View File

@@ -19,6 +19,7 @@ type MQTTClient struct {
Topic string
client mqtt.Client
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -82,7 +83,9 @@ func (mc *MQTTClient) Run(ctx context.Context) error {
return errors.New("mqtt.client unable to get router from context")
}
mc.router = router
mc.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
mc.ctx = moduleContext
mc.cancel = cancel
opts := mqtt.NewClientOptions()
opts.AddBroker(mc.Broker)
@@ -98,6 +101,7 @@ func (mc *MQTTClient) Run(ctx context.Context) error {
}
mc.client = mqtt.NewClient(opts)
defer mc.client.Disconnect(250)
token := mc.client.Connect()
@@ -133,3 +137,7 @@ func (mc *MQTTClient) Output(ctx context.Context, payload any) error {
return token.Error()
}
func (mc *MQTTClient) Stop() {
mc.cancel()
}

View File

@@ -19,6 +19,7 @@ type NATSClient struct {
Subject string
client *nats.Conn
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -71,7 +72,9 @@ func (nc *NATSClient) Run(ctx context.Context) error {
}
nc.router = router
nc.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
nc.ctx = moduleContext
nc.cancel = cancel
client, err := nats.Connect(nc.URL, nats.RetryOnFailedConnect(true))
@@ -121,3 +124,7 @@ func (nc *NATSClient) Output(ctx context.Context, payload any) error {
return err
}
func (nc *NATSClient) Stop() {
nc.cancel()
}

View File

@@ -20,6 +20,7 @@ type PSNClient struct {
router route.RouteIO
decoder *psn.Decoder
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -47,7 +48,9 @@ func (pc *PSNClient) Run(ctx context.Context) error {
return errors.New("psn.client unable to get router from context")
}
pc.router = router
pc.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
pc.ctx = moduleContext
pc.cancel = cancel
addr, err := net.ResolveUDPAddr("udp", "236.10.10.10:56565")
if err != nil {
@@ -104,3 +107,7 @@ func (pc *PSNClient) Run(ctx context.Context) error {
func (pc *PSNClient) Output(ctx context.Context, payload any) error {
return fmt.Errorf("psn.client output is not implemented")
}
func (pc *PSNClient) Stop() {
pc.cancel()
}

View File

@@ -24,6 +24,7 @@ type SerialClient struct {
Mode *serial.Mode
port serial.Port
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -108,7 +109,9 @@ func (sc *SerialClient) Run(ctx context.Context) error {
}
sc.router = router
sc.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
sc.ctx = moduleContext
sc.cancel = cancel
// TODO(jwetzell): shutdown with router.Context properly
go func() {
@@ -180,3 +183,7 @@ func (sc *SerialClient) Output(ctx context.Context, payload any) error {
_, err := sc.port.Write(sc.Framer.Encode(payloadBytes))
return err
}
func (sc *SerialClient) Stop() {
sc.cancel()
}

View File

@@ -29,6 +29,7 @@ type SIPCallServer struct {
UserAgent string
dg *diago.Diago
logger *slog.Logger
cancel context.CancelFunc
}
type SIPCallMessage struct {
@@ -118,7 +119,9 @@ func (scs *SIPCallServer) Run(ctx context.Context) error {
return errors.New("sip.call.server unable to get router from context")
}
scs.router = router
scs.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
scs.ctx = moduleContext
scs.cancel = cancel
diagoLogger := slog.New(slog.NewJSONHandler(io.Discard, nil))
@@ -228,3 +231,7 @@ func (scs *SIPCallServer) Output(ctx context.Context, payload any) error {
}
return errors.New("sip.dtmf.server can only output SipDTMFResponse or SipAudioFileResponse")
}
func (scs *SIPCallServer) Stop() {
scs.cancel()
}

View File

@@ -29,6 +29,7 @@ type SIPDTMFServer struct {
Transport string
Separator string
logger *slog.Logger
cancel context.CancelFunc
}
type SIPDTMFMessage struct {
@@ -120,7 +121,9 @@ func (sds *SIPDTMFServer) Run(ctx context.Context) error {
return errors.New("sip.dtmf.server unable to get router from context")
}
sds.router = router
sds.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
sds.ctx = moduleContext
sds.cancel = cancel
diagoLogger := slog.New(slog.NewJSONHandler(io.Discard, nil))
@@ -243,3 +246,7 @@ func (sds *SIPDTMFServer) Output(ctx context.Context, payload any) error {
return errors.New("sip.dtmf.server can only output SipDTMFResponse or SipAudioFileResponse")
}
func (sds *SIPDTMFServer) Stop() {
sds.cancel()
}

View File

@@ -21,6 +21,7 @@ type TCPClient struct {
router route.RouteIO
Addr *net.TCPAddr
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -94,7 +95,9 @@ func (tc *TCPClient) Run(ctx context.Context) error {
return errors.New("net.tcp.client unable to get router from context")
}
tc.router = router
tc.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
tc.ctx = moduleContext
tc.cancel = cancel
// TODO(jwetzell): shutdown with router.Context properly
go func() {
@@ -176,3 +179,7 @@ func (tc *TCPClient) Output(ctx context.Context, payload any) error {
_, err := tc.conn.Write(tc.framer.Encode(payloadBytes))
return err
}
func (tc *TCPClient) Stop() {
tc.cancel()
}

View File

@@ -27,6 +27,7 @@ type TCPServer struct {
connections []*net.TCPConn
connectionsMu sync.RWMutex
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -105,6 +106,15 @@ ClientRead:
for {
select {
case <-ts.quit:
client.Close()
ts.connectionsMu.Lock()
for i := 0; i < len(ts.connections); i++ {
if ts.connections[i] == client {
ts.connections = slices.Delete(ts.connections, i, i+1)
break
}
}
ts.connectionsMu.Unlock()
return
default:
client.SetDeadline(time.Now().Add(time.Millisecond * 200))
@@ -166,7 +176,9 @@ func (ts *TCPServer) Run(ctx context.Context) error {
return errors.New("net.tcp.server unable to get router from context")
}
ts.router = router
ts.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
ts.ctx = moduleContext
ts.cancel = cancel
listener, err := net.ListenTCP("tcp", ts.Addr)
if err != nil {
@@ -226,3 +238,8 @@ func (ts *TCPServer) Output(ctx context.Context, payload any) error {
}
return fmt.Errorf("net.tcp.server error during output: %s", errorString)
}
func (ts *TCPServer) Stop() {
ts.cancel()
ts.wg.Wait()
}

View File

@@ -17,6 +17,7 @@ type TimeInterval struct {
router route.RouteIO
ticker *time.Ticker
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -56,7 +57,9 @@ func (i *TimeInterval) Run(ctx context.Context) error {
return errors.New("time.interval unable to get router from context")
}
i.router = router
i.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
i.ctx = moduleContext
i.cancel = cancel
ticker := time.NewTicker(time.Millisecond * time.Duration(i.Duration))
i.ticker = ticker
@@ -80,3 +83,7 @@ func (i *TimeInterval) Output(ctx context.Context, payload any) error {
i.ticker.Reset(time.Millisecond * time.Duration(i.Duration))
return nil
}
func (i *TimeInterval) Stop() {
i.cancel()
}

View File

@@ -17,6 +17,7 @@ type TimeTimer struct {
router route.RouteIO
timer *time.Timer
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -57,7 +58,9 @@ func (t *TimeTimer) Run(ctx context.Context) error {
return errors.New("net.tcp.client unable to get router from context")
}
t.router = router
t.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
t.ctx = moduleContext
t.cancel = cancel
t.timer = time.NewTimer(time.Millisecond * time.Duration(t.Duration))
defer t.timer.Stop()
@@ -79,3 +82,7 @@ func (t *TimeTimer) Output(ctx context.Context, payload any) error {
t.timer.Reset(time.Millisecond * time.Duration(t.Duration))
return nil
}
func (t *TimeTimer) Stop() {
t.cancel()
}

View File

@@ -19,6 +19,7 @@ type UDPClient struct {
ctx context.Context
router route.RouteIO
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -80,7 +81,9 @@ func (uc *UDPClient) Run(ctx context.Context) error {
return errors.New("net.udp.client unable to get router from context")
}
uc.router = router
uc.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
uc.ctx = moduleContext
uc.cancel = cancel
err := uc.SetupConn()
if err != nil {
@@ -112,3 +115,7 @@ func (uc *UDPClient) Output(ctx context.Context, payload any) error {
}
return nil
}
func (uc *UDPClient) Stop() {
uc.cancel()
}

View File

@@ -19,6 +19,7 @@ type UDPMulticast struct {
router route.RouteIO
Addr *net.UDPAddr
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -74,7 +75,9 @@ func (um *UDPMulticast) Run(ctx context.Context) error {
return errors.New("net.udp.multicast unable to get router from context")
}
um.router = router
um.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
um.ctx = moduleContext
um.cancel = cancel
client, err := net.ListenMulticastUDP("udp", nil, um.Addr)
if err != nil {
@@ -130,3 +133,7 @@ func (um *UDPMulticast) Output(ctx context.Context, payload any) error {
_, err := um.conn.Write(payloadBytes)
return err
}
func (um *UDPMulticast) Stop() {
um.cancel()
}

View File

@@ -20,6 +20,7 @@ type UDPServer struct {
ctx context.Context
router route.RouteIO
logger *slog.Logger
cancel context.CancelFunc
}
func init() {
@@ -88,7 +89,9 @@ func (us *UDPServer) Run(ctx context.Context) error {
return errors.New("net.udp.server unable to get router from context")
}
us.router = router
us.ctx = ctx
moduleContext, cancel := context.WithCancel(ctx)
us.ctx = moduleContext
us.cancel = cancel
listener, err := net.ListenUDP("udp", us.Addr)
if err != nil {
@@ -129,3 +132,7 @@ func (us *UDPServer) Run(ctx context.Context) error {
func (us *UDPServer) Output(ctx context.Context, payload any) error {
return errors.New("net.udp.server output is not implemented")
}
func (us *UDPServer) Stop() {
us.cancel()
}