package server import ( "errors" "net" "sync/atomic" "github.com/admin-else/strom/mc/proto" "github.com/admin-else/strom/mc/proto_base" "github.com/admin-else/strom/mc/text" ) // Servee wraps a net.Conn in a new proto.Conn configured for the servee side. func Servee(c net.Conn) (ret *proto.Conn) { ret = proto.NewConn() ret.Actor = proto_base.Servee ret.Conn = c ret.R = c ret.W = c ret.Log = ret.Log.With("conn", c.RemoteAddr()) return } type ConnAcceptor func(c net.Conn) (err error) type Factory func(c *proto.Conn) (h ConnAcceptor, err error) // ServeClient accepts a single client connection, creates a handler via the factory, and runs it. func ServeClient(cNet net.Conn, factory Factory) { c := Servee(cNet) defer c.Close() h, err := factory(c) if err != nil { return } err = h(c) if errors.Is(err, StatusServedErr) { return } if err != nil { err = Kick(c, text.Pretty(err.Error()), "") } } // StartServerWithFactory listens on the given address and spawns ServeClient for every accepted connection. func StartServerWithFactory(listenAddr string, factory Factory) (err error) { l, err := net.Listen("tcp", listenAddr) if err != nil { return } var cNet net.Conn for { cNet, err = l.Accept() if err != nil { return } go ServeClient(cNet, factory) } } var ShutDownServerErr = errors.New("server shutting down") // StartServerWithOnConn listens on the given address and calls onConn for every accepted connection. // The server loop stops when onConn returns ShutDownServerErr. func StartServerWithOnConn(listenAddr string, onConn func(c *proto.Conn) (err error)) (err error) { l, err := net.Listen("tcp", listenAddr) if err != nil { return } defer l.Close() running := atomic.Bool{} running.Store(true) for running.Load() { var cNet net.Conn cNet, err = l.Accept() if err != nil { return } go func() { c := Servee(cNet) defer c.Close() connErr := onConn(c) if errors.Is(connErr, ShutDownServerErr) { running.Store(false) } c.Log.Error("closing connection", "err", connErr) if connErr != nil { connErr = Kick(c, text.Pretty(connErr.Error()), "") } }() } err = ShutDownServerErr return }