From b987605cfbbb5ca7b3b4bda0b5a5fdb34c53c8dd Mon Sep 17 00:00:00 2001 From: Kyren223 Date: Sat, 5 Oct 2024 15:27:40 +0300 Subject: [PATCH] feat: basic server connection handling --- cmd/server/server.go | 6 +-- internal/server/handler.go | 32 +++++++++++++++ internal/server/server.go | 79 ++++++++++++++++++++++++++++++++++++ internal/utils/log/log.go | 8 ++-- internal/utils/log/logger.go | 12 +++--- 5 files changed, 123 insertions(+), 14 deletions(-) create mode 100644 internal/server/handler.go create mode 100644 internal/server/server.go diff --git a/cmd/server/server.go b/cmd/server/server.go index a1dee90..78e38f3 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -3,13 +3,11 @@ package main import ( "os" + "github.com/kyren223/eko/internal/server" "github.com/kyren223/eko/internal/utils/log" ) func main() { log.SetDefault(log.NewLogger("Server", os.Stdout, true)) - log.Debug("Eko 'Hello, World!'") - log.Info("Eko 'Hello, World!'") - log.Warn("Eko 'Hello, World!'") - log.Error("Eko 'Hello, World!'") + server.Start() } diff --git a/internal/server/handler.go b/internal/server/handler.go new file mode 100644 index 0000000..68a7cd2 --- /dev/null +++ b/internal/server/handler.go @@ -0,0 +1,32 @@ +package server + +import ( + "net" + "sync" + + "github.com/kyren223/eko/internal/utils/log" +) + +func handleClient(conn net.Conn, wg *sync.WaitGroup) { + log.Info("Handling client... %v", conn.RemoteAddr().String()) + defer log.Info("Disconnecting client: %v", conn.RemoteAddr().String()) + defer conn.Close() + defer wg.Done() + + var request []byte + n, err := conn.Read(request) + if err != nil { + log.Error("Failed reading: %v", err) + return + } + log.Info("Read %v bytes: %v", n, string(request)) + + response := []byte("Server response") + n, err = conn.Write(response) + if err != nil { + log.Error("Failed writing response: %v", err) + return + } + log.Info("Responded successfully") +} + diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..c49df15 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,79 @@ +package server + +import ( + "net" + "os" + "os/signal" + "strconv" + "sync" + "syscall" + + "github.com/kyren223/eko/internal/utils/log" +) + +const PORT int = 7223 + +func Start() { + server, err := NewServer(6969) + if err != nil { + log.Error("Unable to start server: %v", err) + return + } + + var wg sync.WaitGroup + stopChan := make(chan os.Signal, 1) + signal.Notify(stopChan, syscall.SIGINT, syscall.SIGTERM) + wg.Add(1) + go handleInterrupt(server, stopChan, &wg) + + server.Listen() + wg.Wait() +} + +func handleInterrupt(server *Server, stopChan <-chan os.Signal, wg *sync.WaitGroup) { + defer wg.Done() + <-stopChan + log.Info("Interrupt Occurred") + log.Info("Shutting down server...") + server.Close() + log.Info("Waiting for all connections to close") + server.Wait() + log.Info("Server has been shutdown") +} + +type Server struct { + listener net.Listener + wg sync.WaitGroup +} + +func NewServer(port int) (*Server, error) { + listener, err := net.Listen("tcp", ":"+strconv.Itoa(port)) + if err != nil { + return nil, err + } + + log.Info("Created server on port %v", port) + return &Server{listener, sync.WaitGroup{}}, nil +} + +func (s *Server) Listen() { + log.Info("Server started listening... %v", s.listener.Addr().String()) + for { + conn, err := s.listener.Accept() + if err != nil { + break + } + s.wg.Add(1) + go handleClient(conn, &s.wg) + } +} + +// Stop stops the server. The blocked Listen call will be unlocked +func (s *Server) Close() { + s.listener.Close() +} + +// Wait blocks until all active connections to the server are done +func (s *Server) Wait() { + s.wg.Wait() +} diff --git a/internal/utils/log/log.go b/internal/utils/log/log.go index 724b074..366c54d 100644 --- a/internal/utils/log/log.go +++ b/internal/utils/log/log.go @@ -10,17 +10,17 @@ func SetDefault(l *Logger) { } func Debug(message string, a ...any) error { - return logger.Log(LevelDebug, message, a) + return logger.Debug(message, a...) } func Info(message string, a ...any) error { - return logger.Log(LevelInfo, message, a) + return logger.Info(message, a...) } func Warn(message string, a ...any) error { - return logger.Log(LevelWarn, message, a) + return logger.Warn(message, a...) } func Error(message string, a ...any) error { - return logger.Log(LevelError, message, a) + return logger.Error(message, a...) } diff --git a/internal/utils/log/logger.go b/internal/utils/log/logger.go index 735cb9e..891cb086 100644 --- a/internal/utils/log/logger.go +++ b/internal/utils/log/logger.go @@ -2,7 +2,6 @@ package log import ( "fmt" - "go/format" "io" "os" "sync" @@ -29,27 +28,28 @@ func (l *Logger) Log(level Level, message string, a ...any) error { timestamp := time.Now().Format(time.TimeOnly) severity := level.String() + formattedMessage := fmt.Sprintf(message, a...) // TODO: add support for ANSI coloring l.mu.Lock() - _, err := fmt.Fprintf(l.writer, "[%s] [%s/%s]: %s\n", timestamp, l.name, severity, message, a) + _, err := fmt.Fprintf(l.writer, "[%s] [%s/%s]: %s\n", timestamp, l.name, severity, formattedMessage) l.mu.Unlock() return err } func (l *Logger) Debug(message string, a ...any) error { - return l.Log(LevelDebug, message, a) + return l.Log(LevelDebug, message, a...) } func (l *Logger) Info(message string, a ...any) error { - return l.Log(LevelInfo, message, a) + return l.Log(LevelInfo, message, a...) } func (l *Logger) Warn(message string, a ...any) error { - return l.Log(LevelWarn, message, a) + return l.Log(LevelWarn, message, a...) } func (l *Logger) Error(message string, a ...any) error { - return l.Log(LevelError, message, a) + return l.Log(LevelError, message, a...) }