caddy/modules/caddyfs/filesystem.go
Matt Holt 5a6b2f8d1d
Some checks failed
Tests / test (./cmd/caddy/caddy, ~1.24.1, ubuntu-latest, 0, 1.24, linux) (push) Failing after 2m46s
Tests / test (s390x on IBM Z) (push) Has been skipped
Tests / goreleaser-check (push) Has been skipped
Cross-Build / build (~1.24.1, 1.24, aix) (push) Successful in 2m49s
Cross-Build / build (~1.24.1, 1.24, darwin) (push) Successful in 2m10s
Cross-Build / build (~1.24.1, 1.24, dragonfly) (push) Successful in 1m40s
Cross-Build / build (~1.24.1, 1.24, freebsd) (push) Successful in 1m50s
Cross-Build / build (~1.24.1, 1.24, illumos) (push) Successful in 1m49s
Cross-Build / build (~1.24.1, 1.24, linux) (push) Successful in 2m4s
Cross-Build / build (~1.24.1, 1.24, netbsd) (push) Successful in 2m7s
Cross-Build / build (~1.24.1, 1.24, openbsd) (push) Successful in 2m2s
Cross-Build / build (~1.24.1, 1.24, solaris) (push) Successful in 3m30s
Cross-Build / build (~1.24.1, 1.24, windows) (push) Successful in 2m56s
Lint / lint (ubuntu-latest, linux) (push) Failing after 1m17s
Lint / govulncheck (push) Successful in 2m18s
Tests / test (./cmd/caddy/caddy, ~1.24.1, macos-14, 0, 1.24, mac) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy.exe, ~1.24.1, windows-latest, True, 1.24, windows) (push) Has been cancelled
Lint / lint (macos-14, mac) (push) Has been cancelled
Lint / lint (windows-latest, windows) (push) Has been cancelled
events: Refactor; move Event into core, so core can emit events (#6930)
* events: Refactor; move Event into core, so core can emit events

Requires some slight trickery to invert dependencies. We can't have the caddy package import the caddyevents package, because caddyevents imports caddy. Interface to the rescue!

Also add two new events, experimentally: started, and stopping. At the request of a sponsor.

Also rename "Filesystems" to "FileSystems" to match Go convention (unrelated to events, was just bugging me when I noticed it).

* Coupla bug fixes

* lol whoops
2025-03-29 08:15:43 -06:00

113 lines
2.8 KiB
Go

package caddyfs
import (
"encoding/json"
"fmt"
"io/fs"
"go.uber.org/zap"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
)
func init() {
caddy.RegisterModule(Filesystems{})
httpcaddyfile.RegisterGlobalOption("filesystem", parseFilesystems)
}
type moduleEntry struct {
Key string `json:"name,omitempty"`
FileSystemRaw json.RawMessage `json:"file_system,omitempty" caddy:"namespace=caddy.fs inline_key=backend"`
fileSystem fs.FS
}
// Filesystems loads caddy.fs modules into the global filesystem map
type Filesystems struct {
Filesystems []*moduleEntry `json:"filesystems"`
defers []func()
}
func parseFilesystems(d *caddyfile.Dispenser, existingVal any) (any, error) {
p := &Filesystems{}
current, ok := existingVal.(*Filesystems)
if ok {
p = current
}
x := &moduleEntry{}
err := x.UnmarshalCaddyfile(d)
if err != nil {
return nil, err
}
p.Filesystems = append(p.Filesystems, x)
return p, nil
}
// CaddyModule returns the Caddy module information.
func (Filesystems) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "caddy.filesystems",
New: func() caddy.Module { return new(Filesystems) },
}
}
func (xs *Filesystems) Start() error { return nil }
func (xs *Filesystems) Stop() error { return nil }
func (xs *Filesystems) Provision(ctx caddy.Context) error {
// load the filesystem module
for _, f := range xs.Filesystems {
if len(f.FileSystemRaw) > 0 {
mod, err := ctx.LoadModule(f, "FileSystemRaw")
if err != nil {
return fmt.Errorf("loading file system module: %v", err)
}
f.fileSystem = mod.(fs.FS)
}
// register that module
ctx.Logger().Debug("registering fs", zap.String("fs", f.Key))
ctx.FileSystems().Register(f.Key, f.fileSystem)
// remember to unregister the module when we are done
xs.defers = append(xs.defers, func() {
ctx.Logger().Debug("unregistering fs", zap.String("fs", f.Key))
ctx.FileSystems().Unregister(f.Key)
})
}
return nil
}
func (f *Filesystems) Cleanup() error {
for _, v := range f.defers {
v()
}
return nil
}
func (f *moduleEntry) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() {
// key required for now
if !d.Args(&f.Key) {
return d.ArgErr()
}
// get the module json
if !d.NextArg() {
return d.ArgErr()
}
name := d.Val()
modID := "caddy.fs." + name
unm, err := caddyfile.UnmarshalModule(d, modID)
if err != nil {
return err
}
fsys, ok := unm.(fs.FS)
if !ok {
return d.Errf("module %s (%T) is not a supported file system implementation (requires fs.FS)", modID, unm)
}
f.FileSystemRaw = caddyconfig.JSONModuleObject(fsys, "backend", name, nil)
}
return nil
}