tweak semantics for listener, add documentation

This commit is contained in:
Reese Norris
2024-04-06 20:41:59 -07:00
parent f426b1e4a7
commit 8f44e2ddc0

26
main.go
View File

@@ -45,15 +45,20 @@ const TableCreateStatement = `
` `
func StartFSDServer(fsdCtx context.Context) { func StartFSDServer(fsdCtx context.Context) {
// Attempt to resolve the previously-configured listen address
addr, err := net.ResolveTCPAddr("tcp4", SC.FsdListenAddr) addr, err := net.ResolveTCPAddr("tcp4", SC.FsdListenAddr)
if err != nil { if err != nil {
log.Fatal("Error resolving address: " + err.Error()) log.Fatal("Error resolving address: " + err.Error())
} }
// Attempt to open a listener on that address
listener, err := net.ListenTCP("tcp4", addr) listener, err := net.ListenTCP("tcp4", addr)
if err != nil { if err != nil {
log.Fatal("Error listening: " + err.Error()) log.Fatal("Error listening: " + err.Error())
} }
// Defer listener close
// This will force the listener goroutine to encounter an error and promptly close itself
defer func() { defer func() {
closeErr := listener.Close() closeErr := listener.Close()
if closeErr != nil { if closeErr != nil {
@@ -61,29 +66,36 @@ func StartFSDServer(fsdCtx context.Context) {
} }
}() }()
// Listener goroutine // Listen on a separate goroutine
inConnections := make(chan *net.TCPConn) // connChan shall be closed when the listener closes (due to an error or surrounding context closed)
go func(outConnections chan<- *net.TCPConn) { connChan := make(chan *net.TCPConn)
defer close(outConnections) go func(connChan chan<- *net.TCPConn) {
// Guarantee that connChan will be closed when we return
defer close(connChan)
for { for {
// Wait for a connection on the listener
conn, listenerErr := listener.AcceptTCP() conn, listenerErr := listener.AcceptTCP()
if listenerErr != nil { if listenerErr != nil {
return return
} }
// Wait for a consumer on connChan, OR return if the context cancels.
select { select {
case outConnections <- conn: case connChan <- conn:
case <-fsdCtx.Done(): case <-fsdCtx.Done():
return return
} }
} }
}(inConnections) }(connChan)
log.Println("FSD listening") log.Println("FSD listening")
// Poll from connChan, check if the channel is healthy
// Also poll from our context, check if we need to return
for { for {
select { select {
case conn, ok := <-inConnections: case conn, ok := <-connChan:
if !ok { if !ok {
return return
} }