diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-06-07 17:15:27 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-06-07 19:25:11 +0900 |
| commit | e8bb5a622d0c1895b1768a90d0b422ec084db73f (patch) | |
| tree | 46011917ee77bc70c2f6d473b85cee24dfe3e152 /cmd/mbf/main.go | |
| parent | 22e508fe17cdf6be6240e6b73ac5b90bc6bfd77e (diff) | |
internal/rosa: mirror service via external cache
This provides an authenticated implementation of the external cache.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd/mbf/main.go')
| -rw-r--r-- | cmd/mbf/main.go | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/cmd/mbf/main.go b/cmd/mbf/main.go index 86496f98..ae835500 100644 --- a/cmd/mbf/main.go +++ b/cmd/mbf/main.go @@ -14,6 +14,7 @@ package main import ( "context" + "crypto/ed25519" "crypto/sha512" "errors" "fmt" @@ -47,6 +48,19 @@ import ( "hakurei.app/cmd/mbf/internal/pkgserver/ui" ) +// writeFileExcl is like [os.WriteFile], but sets [os.O_EXCL] instead. +func writeFileExcl(name string, data []byte, perm os.FileMode) error { + f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) + if err != nil { + return err + } + _, err = f.Write(data) + if err1 := f.Close(); err1 != nil && err == nil { + err = err1 + } + return err +} + func main() { container.TryArgv0(nil) @@ -187,6 +201,10 @@ func main() { "d", command.StringFlag("$MBF_CACHE_DIR"), "Directory to store cured artifacts", ).Flag( + &cm.mirror, + "r", command.StringFlag("$MBF_REMOTE"), + "URL of mirror service", + ).Flag( &cm.idle, "sched-idle", command.BoolFlag(false), "Set SCHED_IDLE scheduling policy", @@ -462,6 +480,70 @@ func main() { }, ) + c.NewCommand( + "keygen", + "Create keypair for local cache", + func([]string) error { + pub, priv, err := ed25519.GenerateKey(nil) + if err != nil { + return err + } + + return errors.Join(writeFileExcl(filepath.Join( + cm.base, + "ed25519.pub", + ), pub, 0444), writeFileExcl(filepath.Join( + cm.base, + "ed25519", + ), priv, 0400)) + }, + ) + + c.NewCommand( + "serve", + "Export local cache as mirror", + func(args []string) error { + const shutdownTimeout = 15 * time.Second + + if len(args) != 1 { + return errors.New("serve requires 1 argument") + } + + var key ed25519.PrivateKey + if p, err := os.ReadFile(filepath.Join(cm.base, "ed25519")); err != nil { + return err + } else if len(p) != ed25519.PrivateKeySize { + return errors.New("invalid private key") + } else { + key = p + } + + var h http.Handler + if base, err := os.OpenRoot(cm.base); err != nil { + return err + } else { + h = rosa.NewMirror(msg, base, key) + } + + server := http.Server{Addr: args[0], Handler: h} + go func() { + <-ctx.Done() + cc, cancel := context.WithTimeout(context.Background(), shutdownTimeout) + defer cancel() + if err := server.Shutdown(cc); err != nil { + log.Fatal(err) + } + }() + + msg.Verbosef("listening on %q", args[0]) + err := server.ListenAndServe() + if errors.Is(err, http.ErrServerClosed) { + err = nil + } + return err + }, + ) + { var ( flagGentoo string |
