Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

refactor

c5902451905acdaa478f8476844ccd4a510d9ca9 · Keenan Nemetz · 16d ago · parent ec2aba4b

internal/server/server.go → server/server.go +35−68

@@ -8,22 +8,20 @@ import (
8 8 "log/slog"
9 9 "net"
10 10 "net/http"
11 "os"
12 11 "strconv"
13 12 "time"
14 13
15 "github.com/rodent-software/vole/internal/access"
16 "github.com/rodent-software/vole/internal/config"
17 "github.com/rodent-software/vole/internal/identity"
18 "github.com/rodent-software/vole/internal/index"
19 "github.com/rodent-software/vole/internal/lfs"
20 "github.com/rodent-software/vole/internal/locks"
21 "github.com/rodent-software/vole/internal/pages"
22 "github.com/rodent-software/vole/internal/repo"
23 "github.com/rodent-software/vole/internal/runs"
24 "github.com/rodent-software/vole/internal/sshserver"
25 "github.com/rodent-software/vole/internal/transport"
26 "github.com/rodent-software/vole/internal/web"
14 "github.com/rodent-software/vole/ci/runs"
15 "github.com/rodent-software/vole/core/lfs"
16 "github.com/rodent-software/vole/forge"
17 "github.com/rodent-software/vole/forge/config"
18 "github.com/rodent-software/vole/forge/identity"
19 "github.com/rodent-software/vole/forge/index"
20 "github.com/rodent-software/vole/forge/repo"
21 "github.com/rodent-software/vole/server/githttp"
22 "github.com/rodent-software/vole/server/pages"
23 "github.com/rodent-software/vole/server/ssh"
24 "github.com/rodent-software/vole/server/web"
27 25 )
28 26
29 27 type Server struct {
@@ -35,10 +33,10 @@ type Server struct {
35 33 Runs *runs.Store
36 34 Index *index.Store
37 35 LFS *lfs.Store
38 Locks *locks.Store
36 Locks *lfs.LockStore
39 37 Pages *pages.Server
40 Proxy *transport.Proxy
41 SSH *sshserver.Server
38 Proxy *githttp.Proxy
39 SSH *ssh.Server
42 40 Web *web.Web
43 41 Log *slog.Logger
44 42 mux *http.ServeMux
@@ -48,60 +46,27 @@ func New(cfg *config.Config, binPath string, log *slog.Logger) (*Server, error)
48 46 if log == nil {
49 47 log = slog.Default()
50 48 }
51 if err := os.MkdirAll(cfg.ReposDir(), 0o755); err != nil {
52 return nil, err
53 }
54 ident, err := identity.Open(cfg.UsersDB())
55 if err != nil {
56 return nil, fmt.Errorf("%w\nrun `vole init` to create the instance", err)
57 }
58 ident.AuditPath = cfg.AuditLog()
59 ix, err := index.Open(cfg.IndexDB())
60 if err != nil {
61 return nil, fmt.Errorf("open index: %w", err)
62 }
63 runStore, err := runs.Open(cfg.RunsDB())
49 inst, err := forge.Open(cfg, binPath)
64 50 if err != nil {
65 return nil, fmt.Errorf("open run queue: %w", err)
66 }
67 // Access rules live in the instance database beside the roster: only the instance
68 // writes them, and they are keyed by account id, so a copy inside a repository
69 // would be unreadable anyway.
70 acls, err := access.Open(cfg.UsersDB())
71 if err != nil {
72 return nil, fmt.Errorf("open access rules: %w", err)
73 }
74 acls.AuditPath = cfg.AuditLog()
75 // Locks live in the same database as the roster and the access rules: all three are
76 // keyed by account id and none of them can be rebuilt from git, so they are backed
77 // up and restored together or the ids stop resolving.
78 lockStore, err := locks.Open(cfg.UsersDB())
79 if err != nil {
80 return nil, fmt.Errorf("open locks: %w", err)
51 return nil, err
81 52 }
82 lockStore.AuditPath = cfg.AuditLog()
83 rs := repo.New(cfg.ReposDir(), binPath, acls)
84 rs.MaxInputBytes = cfg.ReceiveMaxBytes
85 if n, err := rs.ImportACLs(); err != nil {
86 log.Warn("import access rules from refs/vole/acl", "err", err)
87 } else if n > 0 {
88 log.Info("access rules imported", "repos", n)
53 if inst.ImportedACLs > 0 {
54 log.Info("access rules imported", "repos", inst.ImportedACLs)
89 55 }
90 if n, err := rs.InstallAllHooks(); err != nil {
56 if n, err := inst.Repos.InstallAllHooks(); err != nil {
91 57 log.Warn("install hooks", "err", err)
92 58 } else if n > 0 {
93 59 log.Info("hooks installed", "repos", n)
94 60 }
95 proxy := transport.New(transport.Config{
61 proxy := githttp.New(githttp.Config{
96 62 Root: cfg.ReposDir(),
97 Open: rs.Open,
63 Open: inst.Repos.Open,
98 64 Log: log,
99 65 })
100 lfsStore := lfs.New(cfg.LFSDir(), cfg.LFSObjectMaxBytes)
101 ssh, err := sshserver.New(sshserver.Config{
102 Identity: ident,
103 Repos: rs,
104 LFS: lfsStore,
66 ssh, err := ssh.New(ssh.Config{
67 Identity: inst.Identity,
68 Repos: inst.Repos,
69 LFS: inst.LFS,
105 70 LFSWarnBytes: cfg.LFSWarnBytes,
106 71 Log: log,
107 72 HostKeyPath: cfg.SSHHostKey(),
@@ -109,27 +74,29 @@ func New(cfg *config.Config, binPath string, log *slog.Logger) (*Server, error)
109 74 AuditPath: cfg.AuditLog(),
110 75 SpoolDir: cfg.SpoolDir(),
111 76 RunsDB: cfg.RunsDB(),
112 Runs: runStore,
113 Locks: lockStore,
77 Runs: inst.Runs,
78 Locks: inst.Locks,
114 79 Lease: cfg.Lease(),
115 80 MaxJobsPerRepo: cfg.MaxJobsPerRepo,
116 81 PagesRef: cfg.PagesRef,
117 82 PublicURL: cfg.BaseURL(),
118 83 })
119 84 if err != nil {
85 inst.Close()
120 86 return nil, fmt.Errorf("ssh: %w", err)
121 87 }
122 wp, err := web.New(rs, ix, ident, runStore, cfg)
88 wp, err := web.New(inst.Repos, inst.Index, inst.Identity, inst.Runs, cfg)
123 89 if err != nil {
90 inst.Close()
124 91 return nil, err
125 92 }
126 wp.LFS = lfsStore
127 wp.Locks = lockStore
93 wp.LFS = inst.LFS
94 wp.Locks = inst.Locks
128 95 wp.Logger = func(format string, args ...any) { log.Warn(fmt.Sprintf(format, args...)) }
129 96
130 97 s := &Server{
131 Cfg: cfg, Repos: rs, Identity: ident, Runs: runStore, Index: ix, LFS: lfsStore, Locks: lockStore,
132 Proxy: proxy, SSH: ssh, Web: wp, Log: log,
98 Cfg: cfg, Repos: inst.Repos, Identity: inst.Identity, Runs: inst.Runs, Index: inst.Index,
99 LFS: inst.LFS, Locks: inst.Locks, Proxy: proxy, SSH: ssh, Web: wp, Log: log,
133 100 }
134 101 // Sites are opt-in: without a pages domain there is no host to serve them on,
135 102 // and an instance that never wanted them pays no processes for the idea.
@@ -140,7 +107,7 @@ func New(cfg *config.Config, binPath string, log *slog.Logger) (*Server, error)
140 107 Procs: cfg.PagesProcs,
141 108 CacheBytes: cfg.PagesCacheBytes,
142 109 Log: log,
143 }, rs)
110 }, inst.Repos)
144 111 }
145 112 s.mux = s.routes()
146 113 // Background loops start here rather than in Run: a caller that serves the