aboutsummaryrefslogtreecommitdiff
path: root/internal/server/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/server/server.go')
-rw-r--r--internal/server/server.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/server/server.go b/internal/server/server.go
new file mode 100644
index 0000000..1c28cd5
--- /dev/null
+++ b/internal/server/server.go
@@ -0,0 +1,70 @@
+package server
+
+import (
+ "context"
+ "encoding/hex"
+ "fmt"
+ "log/slog"
+ "net"
+ "sync"
+
+ "go.neonxp.ru/qchat/internal/chat"
+ "go.neonxp.ru/qchat/internal/config"
+ "golang.org/x/crypto/ssh"
+)
+
+type Server struct {
+ cfg *config.Config
+ chat *chat.Chat
+}
+
+func New(cfg *config.Config, ch *chat.Chat) *Server {
+ return &Server{
+ cfg: cfg,
+ chat: ch,
+ }
+}
+
+func (s *Server) Run(ctx context.Context) error {
+ config := &ssh.ServerConfig{
+ PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
+ return &ssh.Permissions{
+ ExtraData: map[any]any{
+ "identify": hex.EncodeToString(pubKey.Marshal()),
+ },
+ }, nil
+ },
+ }
+
+ private, err := ssh.ParsePrivateKey([]byte(s.cfg.Server.PrivateKey))
+ if err != nil {
+ return fmt.Errorf("failed to parse private key: %w", err)
+ }
+ config.AddHostKey(private)
+ listener, err := net.Listen("tcp", s.cfg.Server.Addr)
+ if err != nil {
+ return fmt.Errorf("failed to parse private key: %w", err)
+ }
+ go func() {
+ <-ctx.Done()
+ listener.Close()
+ }()
+
+ wg := sync.WaitGroup{}
+ defer wg.Wait()
+
+ slog.InfoContext(ctx, "started server at", slog.String("addr", s.cfg.Server.Addr))
+
+ for {
+ nConn, err := listener.Accept()
+ if err != nil {
+ slog.ErrorContext(ctx, "failed to accept incoming connection", slog.Any("err", err))
+ continue
+ }
+ wg.Go(func() {
+ if err := s.serveConn(ctx, nConn, config); err != nil {
+ slog.ErrorContext(ctx, "connection error", slog.Any("err", err))
+ }
+ })
+ }
+}