1package server
 2
 3import (
 4	"context"
 5
 6	"github.com/charmbracelet/log"
 7
 8	"github.com/charmbracelet/soft-serve/server/backend"
 9	"github.com/charmbracelet/soft-serve/server/config"
10	"github.com/charmbracelet/ssh"
11	"golang.org/x/sync/errgroup"
12)
13
14var (
15	logger = log.WithPrefix("server")
16)
17
18// Server is the Soft Serve server.
19type Server struct {
20	SSHServer *SSHServer
21	GitDaemon *GitDaemon
22	Config    *config.Config
23	Backend   backend.Backend
24	Access    backend.AccessMethod
25}
26
27// NewServer returns a new *ssh.Server configured to serve Soft Serve. The SSH
28// server key-pair will be created if none exists. An initial admin SSH public
29// key can be provided with authKey. If authKey is provided, access will be
30// restricted to that key. If authKey is not provided, the server will be
31// publicly writable until configured otherwise by cloning the `config` repo.
32func NewServer(cfg *config.Config) (*Server, error) {
33	var err error
34	srv := &Server{
35		Config:  cfg,
36		Backend: cfg.Backend,
37		Access:  cfg.Access,
38	}
39	srv.SSHServer, err = NewSSHServer(cfg)
40	if err != nil {
41		return nil, err
42	}
43
44	srv.GitDaemon, err = NewGitDaemon(cfg)
45	if err != nil {
46		return nil, err
47	}
48
49	return srv, nil
50}
51
52// Start starts the SSH server.
53func (s *Server) Start() error {
54	var errg errgroup.Group
55	errg.Go(func() error {
56		log.Print("Starting Git daemon", "addr", s.Config.Git.ListenAddr)
57		if err := s.GitDaemon.Start(); err != ErrServerClosed {
58			return err
59		}
60		return nil
61	})
62	errg.Go(func() error {
63		log.Print("Starting SSH server", "addr", s.Config.SSH.ListenAddr)
64		if err := s.SSHServer.ListenAndServe(); err != ssh.ErrServerClosed {
65			return err
66		}
67		return nil
68	})
69	return errg.Wait()
70}
71
72// Shutdown lets the server gracefully shutdown.
73func (s *Server) Shutdown(ctx context.Context) error {
74	var errg errgroup.Group
75	errg.Go(func() error {
76		return s.GitDaemon.Shutdown(ctx)
77	})
78	errg.Go(func() error {
79		return s.SSHServer.Shutdown(ctx)
80	})
81	return errg.Wait()
82}
83
84// Close closes the SSH server.
85func (s *Server) Close() error {
86	var errg errgroup.Group
87	errg.Go(func() error {
88		return s.SSHServer.Close()
89	})
90	errg.Go(func() error {
91		return s.GitDaemon.Close()
92	})
93	return errg.Wait()
94}