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}