server.go

 1package server
 2
 3import (
 4	"context"
 5	"fmt"
 6	"log"
 7
 8	"github.com/charmbracelet/soft-serve/config"
 9	appCfg "github.com/charmbracelet/soft-serve/internal/config"
10	"github.com/charmbracelet/soft-serve/internal/tui"
11	"github.com/charmbracelet/wish"
12	bm "github.com/charmbracelet/wish/bubbletea"
13	gm "github.com/charmbracelet/wish/git"
14	lm "github.com/charmbracelet/wish/logging"
15	rm "github.com/charmbracelet/wish/recover"
16	"github.com/gliderlabs/ssh"
17)
18
19// Server is the Soft Serve server.
20type Server struct {
21	SSHServer *ssh.Server
22	Config    *config.Config
23	config    *appCfg.Config
24}
25
26// NewServer returns a new *ssh.Server configured to serve Soft Serve. The SSH
27// server key-pair will be created if none exists. An initial admin SSH public
28// key can be provided with authKey. If authKey is provided, access will be
29// restricted to that key. If authKey is not provided, the server will be
30// publicly writable until configured otherwise by cloning the `config` repo.
31func NewServer(cfg *config.Config) *Server {
32	ac, err := appCfg.NewConfig(cfg)
33	if err != nil {
34		log.Fatal(err)
35	}
36	mw := []wish.Middleware{
37		rm.MiddlewareWithLogger(
38			cfg.ErrorLog,
39			softMiddleware(ac),
40			bm.Middleware(tui.SessionHandler(ac)),
41			gm.Middleware(cfg.RepoPath, ac),
42			lm.Middleware(),
43		),
44	}
45	s, err := wish.NewServer(
46		ssh.PublicKeyAuth(ac.PublicKeyHandler),
47		ssh.PasswordAuth(ac.PasswordHandler),
48		wish.WithAddress(fmt.Sprintf("%s:%d", cfg.BindAddr, cfg.Port)),
49		wish.WithHostKeyPath(cfg.KeyPath),
50		wish.WithMiddleware(mw...),
51	)
52	if err != nil {
53		log.Fatalln(err)
54	}
55	return &Server{
56		SSHServer: s,
57		Config:    cfg,
58		config:    ac,
59	}
60}
61
62// Reload reloads the server configuration.
63func (srv *Server) Reload() error {
64	return srv.config.Reload()
65}
66
67// Start starts the SSH server.
68func (srv *Server) Start() error {
69	return srv.SSHServer.ListenAndServe()
70}
71
72// Shutdown lets the server gracefully shutdown.
73func (srv *Server) Shutdown(ctx context.Context) error {
74	return srv.SSHServer.Shutdown(ctx)
75}
76
77// Close closes the SSH server.
78func (srv *Server) Close() error {
79	return srv.SSHServer.Close()
80}