about summary refs log tree commit diff stats
path: root/internal/storage
diff options
context:
space:
mode:
authorAlan Pearce2025-01-29 22:00:45 +0100
committerAlan Pearce2025-01-29 23:27:45 +0100
commit3162ceaa0f7997742f8c2fce1c9660e8e86ad5bb (patch)
tree14c424b8ef8b9238e69393cd7da1d0af6833526e /internal/storage
parenta93b5ad88ea3cf742cf03fdeeb95f63865f08374 (diff)
downloadwebsite-3162ceaa0f7997742f8c2fce1c9660e8e86ad5bb.tar.lz
website-3162ceaa0f7997742f8c2fce1c9660e8e86ad5bb.tar.zst
website-3162ceaa0f7997742f8c2fce1c9660e8e86ad5bb.zip
use buffers as interface to storage
Diffstat (limited to 'internal/storage')
-rw-r--r--internal/storage/file.go5
-rw-r--r--internal/storage/files/file.go45
-rw-r--r--internal/storage/files/reader.go9
-rw-r--r--internal/storage/files/writer.go74
-rw-r--r--internal/storage/interface.go19
5 files changed, 63 insertions, 89 deletions
diff --git a/internal/storage/file.go b/internal/storage/file.go
index f588bf3..38824b6 100644
--- a/internal/storage/file.go
+++ b/internal/storage/file.go
@@ -1,8 +1,9 @@
 package storage
 
 import (
-	"io"
 	"time"
+
+	"go.alanpearce.eu/website/internal/buffer"
 )
 
 type File struct {
@@ -10,7 +11,7 @@ type File struct {
 	ContentType  string
 	LastModified time.Time
 	Etag         string
-	Encodings    map[string]io.ReadSeekCloser
+	Encodings    map[string]*buffer.Buffer
 }
 
 func (f *File) AvailableEncodings() []string {
diff --git a/internal/storage/files/file.go b/internal/storage/files/file.go
index a71811c..b79c43c 100644
--- a/internal/storage/files/file.go
+++ b/internal/storage/files/file.go
@@ -10,19 +10,18 @@ import (
 	"strings"
 
 	"gitlab.com/tozd/go/errors"
+	"go.alanpearce.eu/website/internal/buffer"
 	"go.alanpearce.eu/website/internal/storage"
 )
 
-type File struct {
-	storage.File
-}
+type Content io.ReadSeekCloser
 
 var encodings = map[string]string{
 	"br":   ".br",
 	"gzip": ".gz",
 }
 
-func (r *Reader) OpenFile(path string, filename string) (*File, error) {
+func (r *Reader) OpenFile(path string, filename string) (*storage.File, error) {
 	f, err := os.Open(filename)
 	if err != nil {
 		return nil, errors.WithMessage(err, "could not open file for reading")
@@ -37,15 +36,18 @@ func (r *Reader) OpenFile(path string, filename string) (*File, error) {
 		return nil, errors.WithMessage(err, "could not calculate etag")
 	}
 
-	file := &File{
-		File: storage.File{
-			Path:         path,
-			ContentType:  mime.TypeByExtension(filepath.Ext(filename)),
-			LastModified: stat.ModTime(),
-			Etag:         etag,
-			Encodings: map[string]io.ReadSeekCloser{
-				"identity": f,
-			},
+	buf := new(buffer.Buffer)
+	if _, err := f.WriteTo(buf); err != nil {
+		return nil, errors.WithMessage(err, "could not read file")
+	}
+
+	file := &storage.File{
+		Path:         path,
+		ContentType:  mime.TypeByExtension(filepath.Ext(filename)),
+		LastModified: stat.ModTime(),
+		Etag:         etag,
+		Encodings: map[string]*buffer.Buffer{
+			"identity": buf,
 		},
 	}
 
@@ -58,10 +60,12 @@ func (r *Reader) OpenFile(path string, filename string) (*File, error) {
 
 			return nil, errors.WithMessagef(err, "could not stat file %s", filename+suffix)
 		}
-		file.Encodings[enc], err = os.Open(filename + suffix)
+		bytes, err := os.ReadFile(filename + suffix)
 		if err != nil {
 			return nil, errors.WithMessagef(err, "could not read file %s", filename+suffix)
 		}
+		buf := buffer.NewBuffer(bytes)
+		file.Encodings[enc] = buf
 	}
 
 	return file, nil
@@ -76,23 +80,12 @@ func etag(f io.Reader) (string, error) {
 	return fmt.Sprintf(`W/"%x"`, hash.Sum(nil)), nil
 }
 
-func (f *File) Close() error {
-	var errs []error
-	for _, enc := range f.Encodings {
-		if err := enc.Close(); err != nil {
-			errs = append(errs, err)
-		}
-	}
-
-	return errors.Join(errs...)
-}
-
 func pathNameToFileName(pathname string) string {
 	if strings.HasSuffix(pathname, "/") {
 		pathname = pathname + "index.html"
 	}
 
-	return pathname
+	return strings.TrimPrefix(pathname, "/")
 }
 
 func fileNameToPathName(filename string) string {
diff --git a/internal/storage/files/reader.go b/internal/storage/files/reader.go
index 425436b..fff37da 100644
--- a/internal/storage/files/reader.go
+++ b/internal/storage/files/reader.go
@@ -5,6 +5,7 @@ import (
 	"path/filepath"
 	"strings"
 
+	"go.alanpearce.eu/website/internal/storage"
 	"go.alanpearce.eu/x/log"
 
 	"gitlab.com/tozd/go/errors"
@@ -13,14 +14,14 @@ import (
 type Reader struct {
 	root  string
 	log   *log.Logger
-	files map[string]*File
+	files map[string]*storage.File
 }
 
 func NewReader(path string, log *log.Logger) (*Reader, error) {
 	r := &Reader{
 		root:  path,
 		log:   log,
-		files: make(map[string]*File),
+		files: make(map[string]*storage.File),
 	}
 	if err := r.registerContentFiles(); err != nil {
 		return nil, errors.WithMessagef(err, "registering content files")
@@ -69,8 +70,8 @@ func (r *Reader) registerContentFiles() error {
 	return nil
 }
 
-func (r *Reader) GetFile(urlPath string) *File {
-	return r.files[urlPath]
+func (r *Reader) GetFile(urlPath string) (*storage.File, error) {
+	return r.files[urlPath], nil
 }
 
 func (r *Reader) CanonicalisePath(path string) (cPath string, differs bool) {
diff --git a/internal/storage/files/writer.go b/internal/storage/files/writer.go
index ce498e7..40cf364 100644
--- a/internal/storage/files/writer.go
+++ b/internal/storage/files/writer.go
@@ -2,14 +2,15 @@ package files
 
 import (
 	"compress/gzip"
-	"context"
 	"io"
 	"os"
 	"path/filepath"
+	"time"
 
+	"go.alanpearce.eu/website/internal/buffer"
+	"go.alanpearce.eu/website/internal/storage"
 	"go.alanpearce.eu/x/log"
 
-	"github.com/a-h/templ"
 	"github.com/andybalholm/brotli"
 	"gitlab.com/tozd/go/errors"
 )
@@ -29,66 +30,49 @@ type Options struct {
 	Compress bool
 }
 
-func NewWriter(outputDirectory string, logger *log.Logger, opts *Options) *Files {
+func NewWriter(outputDirectory string, logger *log.Logger, opts *Options) (*Files, error) {
 	return &Files{
 		outputDirectory: outputDirectory,
 		options:         opts,
 		log:             logger,
+	}, nil
+}
+
+func (f *Files) NewFile(path string) *storage.File {
+	return &storage.File{
+		Path:         path,
+		ContentType:  "",
+		LastModified: time.Time{},
+		Etag:         "",
+		Encodings: map[string]*buffer.Buffer{
+			"identity": nil,
+		},
 	}
 }
 
-func (f *Files) Open(filename string) (io.ReadCloser, error) {
+func (f *Files) OpenRead(filename string) (io.ReadCloser, error) {
 	return os.Open(f.join(filename))
 }
 
-func (f *Files) OutputToFile(output io.Reader, filename string) error {
-	if err := f.Mkdirp(filepath.Dir(filename)); err != nil {
-		return err
-	}
-	f.log.Debug("outputting file", "filename", filename)
-	file, err := f.OpenFileAndVariants(filename)
-	if err != nil {
-		return errors.WithMessage(err, "could not open output file")
-	}
-	defer file.Close()
-
-	if _, err := io.Copy(file, output); err != nil {
-		return errors.WithMessage(err, "could not write output file")
-	}
-
-	return nil
+func (f *Files) OpenWrite(filename string) (io.WriteCloser, error) {
+	return openFileWrite(f.join(filename))
 }
 
-func (f *Files) RenderToFile(component templ.Component, filename string) error {
-	if err := f.Mkdirp(filepath.Dir(filename)); err != nil {
-		return err
-	}
-	f.log.Debug("outputting file", "filename", filename)
-	file, err := f.OpenFileAndVariants(filename)
+func (f *Files) Write(pathname string, content *buffer.Buffer) error {
+	filename := pathNameToFileName(pathname)
+	err := f.Mkdirp(filepath.Dir(filename))
 	if err != nil {
-		return errors.WithMessage(err, "could not open output file")
-	}
-	defer file.Close()
-
-	if err := component.Render(context.TODO(), file); err != nil {
-		return errors.WithMessage(err, "could not write output file")
+		return errors.WithMessage(err, "could not create directory")
 	}
 
-	return nil
-}
-
-func (f *Files) WriterToFile(writer io.WriterTo, filename string) error {
-	if err := f.Mkdirp(filepath.Dir(filename)); err != nil {
-		return err
-	}
-	f.log.Debug("outputting file", "filename", filename)
-	file, err := f.OpenFileAndVariants(filename)
+	fd, err := openFileWrite(f.join(filename))
 	if err != nil {
-		return errors.WithMessage(err, "could not open output file")
+		return errors.WithMessagef(err, "could not open output file")
 	}
-	defer file.Close()
+	defer fd.Close()
 
-	if _, err := writer.WriteTo(file); err != nil {
+	_, err = fd.Write(content.Bytes())
+	if err != nil {
 		return errors.WithMessage(err, "could not write output file")
 	}
 
@@ -170,7 +154,7 @@ func (f *Files) OpenFileAndVariants(filename string) (io.WriteCloser, error) {
 
 func (f *Files) Mkdirp(dir string) error {
 	f.log.Debug("creating directory", "dir", dir)
-	err := os.MkdirAll(filepath.Join(f.outputDirectory, dir), 0755)
+	err := os.MkdirAll(f.join(dir), 0755)
 
 	return errors.WithMessage(err, "could not create directory")
 }
diff --git a/internal/storage/interface.go b/internal/storage/interface.go
index 6c8f3cd..c167a49 100644
--- a/internal/storage/interface.go
+++ b/internal/storage/interface.go
@@ -1,21 +1,16 @@
 package storage
 
 import (
-	"io"
-
-	"github.com/a-h/templ"
+	"go.alanpearce.eu/website/internal/buffer"
 )
 
+type Reader interface {
+	GetFile(path string) (*File, error)
+	CanonicalisePath(path string) (cPath string, differs bool)
+}
+
 type Writer interface {
 	Mkdirp(path string) error
 
-	Open(filename string) (io.ReadCloser, error)
-
-	OpenFileAndVariants(filename string) (io.WriteCloser, error)
-
-	OutputToFile(output io.Reader, filename string) error
-
-	RenderToFile(component templ.Component, filename string) error
-
-	WriterToFile(writer io.WriterTo, filename string) error
+	Write(pathname string, content *buffer.Buffer) error
 }